1 // Copyright (C) 2007 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP 4 #define DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP 5 6 #include "multithreaded_object_extension.h" 7 #include "create_new_thread_extension.h" 8 9 10 namespace dlib 11 { 12 13 // ---------------------------------------------------------------------------------------- 14 15 multithreaded_object:: multithreaded_object()16 multithreaded_object ( 17 ): 18 s(m_), 19 is_running_(false), 20 should_stop_(false), 21 threads_started(0) 22 { 23 } 24 25 // ---------------------------------------------------------------------------------------- 26 27 multithreaded_object:: ~multithreaded_object()28 ~multithreaded_object ( 29 ) 30 { 31 try 32 { 33 DLIB_ASSERT(number_of_threads_alive() == 0, 34 "\tmultithreaded_object::~multithreaded_object()" 35 << "\n\tYou have let a multithreaded object destruct itself before terminating its threads" 36 << "\n\tthis: " << this 37 ); 38 } 39 catch (std::exception& e) 40 { 41 std::cerr << e.what() << std::endl; 42 assert(false); 43 abort(); 44 } 45 } 46 47 // ---------------------------------------------------------------------------------------- 48 49 void multithreaded_object:: clear()50 clear ( 51 ) 52 { 53 auto_mutex M(m_); 54 stop(); 55 wait(); 56 dead_threads.clear(); 57 is_running_ = false; 58 should_stop_ = false; 59 } 60 61 // ---------------------------------------------------------------------------------------- 62 63 bool multithreaded_object:: is_running() const64 is_running ( 65 ) const 66 { 67 auto_mutex M(m_); 68 return is_running_; 69 } 70 71 // ---------------------------------------------------------------------------------------- 72 73 unsigned long multithreaded_object:: number_of_threads_registered() const74 number_of_threads_registered ( 75 ) const 76 { 77 auto_mutex M(m_); 78 return thread_ids.size() + dead_threads.size(); 79 } 80 81 // ---------------------------------------------------------------------------------------- 82 83 unsigned long multithreaded_object:: number_of_threads_alive() const84 number_of_threads_alive ( 85 ) const 86 { 87 auto_mutex M(m_); 88 return threads_started; 89 } 90 91 // ---------------------------------------------------------------------------------------- 92 93 void multithreaded_object:: wait() const94 wait ( 95 ) const 96 { 97 auto_mutex M(m_); 98 99 DLIB_ASSERT(thread_ids.is_in_domain(get_thread_id()) == false, 100 "\tvoid multithreaded_object::wait()" 101 << "\n\tYou can NOT call this function from one of the threads registered in this object" 102 << "\n\tthis: " << this 103 ); 104 105 while (threads_started > 0) 106 s.wait(); 107 } 108 109 // ---------------------------------------------------------------------------------------- 110 111 void multithreaded_object:: start()112 start ( 113 ) 114 { 115 auto_mutex M(m_); 116 const unsigned long num_threads_registered = dead_threads.size() + thread_ids.size(); 117 // start any dead threads 118 for (unsigned long i = threads_started; i < num_threads_registered; ++i) 119 { 120 if (create_new_thread<multithreaded_object,&multithreaded_object::thread_helper>(*this) == false) 121 { 122 should_stop_ = true; 123 is_running_ = false; 124 throw thread_error(); 125 } 126 ++threads_started; 127 } 128 is_running_ = true; 129 should_stop_ = false; 130 s.broadcast(); 131 } 132 133 // ---------------------------------------------------------------------------------------- 134 135 void multithreaded_object:: pause()136 pause ( 137 ) 138 { 139 auto_mutex M(m_); 140 is_running_ = false; 141 } 142 143 // ---------------------------------------------------------------------------------------- 144 145 void multithreaded_object:: stop()146 stop ( 147 ) 148 { 149 auto_mutex M(m_); 150 should_stop_ = true; 151 is_running_ = false; 152 s.broadcast(); 153 } 154 155 // ---------------------------------------------------------------------------------------- 156 157 bool multithreaded_object:: should_stop() const158 should_stop ( 159 ) const 160 { 161 auto_mutex M(m_); 162 DLIB_ASSERT(thread_ids.is_in_domain(get_thread_id()), 163 "\tbool multithreaded_object::should_stop()" 164 << "\n\tYou can only call this function from one of the registered threads in this object" 165 << "\n\tthis: " << this 166 ); 167 while (is_running_ == false && should_stop_ == false) 168 s.wait(); 169 return should_stop_; 170 } 171 172 // ---------------------------------------------------------------------------------------- 173 174 multithreaded_object::raii_thread_helper:: raii_thread_helper(multithreaded_object & self_,thread_id_type id_)175 raii_thread_helper( 176 multithreaded_object& self_, 177 thread_id_type id_ 178 ) : self(self_), id(id_){} 179 180 multithreaded_object::raii_thread_helper:: ~raii_thread_helper()181 ~raii_thread_helper() 182 { 183 auto_mutex M(self.m_); 184 if (self.thread_ids.is_in_domain(id)) 185 { 186 mfp temp; 187 thread_id_type id_temp; 188 self.thread_ids.remove(id,id_temp,temp); 189 // put this thread's registered function back into the dead_threads queue 190 self.dead_threads.enqueue(temp); 191 } 192 193 --self.threads_started; 194 // If this is the last thread to terminate then 195 // signal that that is the case. 196 if (self.threads_started == 0) 197 { 198 self.is_running_ = false; 199 self.should_stop_ = false; 200 self.s.broadcast(); 201 } 202 } 203 204 // ---------------------------------------------------------------------------------------- 205 206 void multithreaded_object:: thread_helper()207 thread_helper( 208 ) 209 { 210 mfp mf; 211 thread_id_type id = get_thread_id(); 212 213 // this guy's destructor does all the necessary cleanup in this function 214 raii_thread_helper raii(*this, id); 215 216 // if there is a dead_thread sitting around then pull it 217 // out and put it into mf 218 { 219 auto_mutex M(m_); 220 if (dead_threads.size() > 0) 221 { 222 dead_threads.dequeue(mf); 223 mfp temp(mf); 224 thread_ids.add(id,temp); 225 } 226 } 227 228 if (mf.is_set()) 229 { 230 // call the registered thread function 231 mf(); 232 } 233 } 234 235 // ---------------------------------------------------------------------------------------- 236 237 } 238 239 #endif // DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP 240 241 242