/* threads_1: Multithreading support library Yauheni A. Akhotnikau (C) 2002-2003 eao197@yahoo.com ------------------------------------------------- Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. ------------------------------------------------- */ /* Демострация работы condition variable. */ #include <iostream> #include <cpp_util_2/h/defs.hpp> #include <threads_1/h/threads.hpp> /* Класс нити, которая ожидает наступление события (срабатывания condition variable), печатает на экран сообщение и завершается. */ class type1_thread_t : public threads_1::thread_t { private : // Семафор, который необходим // для ожидания condition variable. const threads_1::mutex_sem_t & m_sem; // Condition variable, срабатывание // которой ожидается нитью. const threads_1::cond_var_t & m_cv; public : type1_thread_t( const threads_1::mutex_sem_t & sem, const threads_1::cond_var_t & cv ); virtual ~type1_thread_t(); protected : // Данный метод выполняет все действия нити. virtual void body(); }; type1_thread_t::type1_thread_t( const threads_1::mutex_sem_t & sem, const threads_1::cond_var_t & cv ) : m_sem( sem ), m_cv( cv ) { } type1_thread_t::~type1_thread_t() { } void type1_thread_t::body() { std::cout << "Type1 thread started\n" << std::flush; { // Захватываем mutex. threads_1::mutex_sem_t::lock_t lock( m_sem ); // Ожидаем срабатывания condition variable. m_cv.wait( m_sem ); // Condition variable сработала. // Если бы здесь выполнялись какие-то // операции над разделяемыми данными, то // этому бы никто не мешал, т.к. данная // нить владеет m_sem. std::cout << "Condition variable signaled\n" << std::flush; } std::cout << "Type1 thread finished\n" << std::flush; } /* Класс нити, которая: - засыпает на 1 секунду, - затем захватывает mutex1 и засыпает еще на 2 секунды, - затем порождает нотификацию, освобождает mutex1, - затем засыпает на 1 секунду, - захватывает mutex2, порождает нотификацию, - завершает свою работу. */ class type2_thread_t : public threads_1::thread_t { private : // Семафоры, который необходим // для ожидания condition variable. const threads_1::mutex_sem_t & m_sem1; const threads_1::mutex_sem_t & m_sem2; // Condition variable, срабатывание // которой ожидается нитью. threads_1::cond_var_t & m_cv; public : type2_thread_t( const threads_1::mutex_sem_t & sem1, const threads_1::mutex_sem_t & sem2, threads_1::cond_var_t & cv ); virtual ~type2_thread_t(); protected : // Данный метод выполняет все действия нити. virtual void body(); }; type2_thread_t::type2_thread_t( const threads_1::mutex_sem_t & sem1, const threads_1::mutex_sem_t & sem2, threads_1::cond_var_t & cv ) : m_sem1( sem1 ), m_sem2( sem2 ), m_cv( cv ) { } type2_thread_t::~type2_thread_t() { } void type2_thread_t::body() { std::cout << "Type2 thread started\n" << std::flush; { sleep( 1000 ); { // Захватываем mutex. threads_1::mutex_sem_t::lock_t lock( m_sem1 ); std::cout << "Mutex locked #1" << std::endl; sleep( 2000 ); std::cout << "Notification to all" << std::endl; m_cv.notify_all(); } sleep( 1000 ); { // Захватываем mutex. threads_1::mutex_sem_t::lock_t lock( m_sem2 ); std::cout << "Mutex locked #2" << std::endl; std::cout << "Notification to all" << std::endl; m_cv.notify_all(); } } std::cout << "Type2 thread finished\n" << std::flush; } /* Класс нити, которая сначала засыпает на 2 секунды, затем ожидает наступления события (срабатывания condition variable), печатает на экран сообщение и завершается. Данная нить должна завершить свою работу только после того, как нить типа 2 второй раз отошлет нотификацию. */ class type3_thread_t : public threads_1::thread_t { private : // Семафор, который необходим // для ожидания condition variable. const threads_1::mutex_sem_t & m_sem; // Condition variable, срабатывание // которой ожидается нитью. const threads_1::cond_var_t & m_cv; public : type3_thread_t( const threads_1::mutex_sem_t & sem, const threads_1::cond_var_t & cv ); virtual ~type3_thread_t(); protected : // Данный метод выполняет все действия нити. virtual void body(); }; type3_thread_t::type3_thread_t( const threads_1::mutex_sem_t & sem, const threads_1::cond_var_t & cv ) : m_sem( sem ), m_cv( cv ) { } type3_thread_t::~type3_thread_t() { } void type3_thread_t::body() { std::cout << "Type3 thread started\n" << std::flush; { sleep( 2000 ); // Захватываем mutex. threads_1::mutex_sem_t::lock_t lock( m_sem ); // Ожидаем срабатывания condition variable. m_cv.wait( m_sem ); // Condition variable сработала. // Если бы здесь выполнялись какие-то // операции над разделяемыми данными, то // этому бы никто не мешал, т.к. данная // нить владеет m_sem. std::cout << "Condition variable signaled\n" << std::flush; } sleep( 1000 ); std::cout << "Type3 thread finished\n" << std::flush; } int main() { threads_1::mutex_sem_t sem1; threads_1::mutex_sem_t sem2; threads_1::cond_var_t cv; type1_thread_t th1_1( sem1, cv ); type1_thread_t th1_2( sem1, cv ); type1_thread_t th1_3( sem1, cv ); type1_thread_t th1_4( sem1, cv ); type1_thread_t th1_5( sem1, cv ); type2_thread_t th2_1( sem1, sem2, cv ); type3_thread_t th3_1( sem2, cv ); type3_thread_t th3_2( sem2, cv ); type3_thread_t th3_3( sem2, cv ); type3_thread_t th3_4( sem2, cv ); type3_thread_t th3_5( sem2, cv ); th1_1.start(); th1_2.start(); th1_3.start(); th1_4.start(); th1_5.start(); th2_1.start(); th3_1.start(); th3_2.start(); th3_3.start(); th3_4.start(); th3_5.start(); th1_1.wait(); th1_2.wait(); th1_3.wait(); th1_4.wait(); th1_5.wait(); th2_1.wait(); th3_1.wait(); th3_2.wait(); th3_3.wait(); th3_4.wait(); th3_5.wait(); return 0; }
00001 /* 00002 00003 threads_1: Multithreading support library 00004 Yauheni A. Akhotnikau (C) 2002-2003 00005 eao197@yahoo.com 00006 ------------------------------------------------- 00007 00008 Permission is granted to anyone to use this software for any purpose on any 00009 computer system, and to redistribute it freely, subject to the following 00010 restrictions: 00011 00012 1. This software is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00015 00016 2. The origin of this software must not be misrepresented, either by 00017 explicit claim or by omission. 00018 00019 3. Altered versions must be plainly marked as such, and must not be 00020 misrepresented as being the original software. 00021 00022 ------------------------------------------------- 00023 00024 */ 00025 /* 00026 Демострация работы condition variable. 00027 */ 00028 00029 #include <iostream> 00030 00031 #include <cpp_util_2/h/defs.hpp> 00032 00033 #include <threads_1/h/threads.hpp> 00034 00035 /* 00036 Класс нити, которая ожидает наступление 00037 события (срабатывания condition variable), 00038 печатает на экран сообщение и завершается. 00039 */ 00040 class type1_thread_t : 00041 public threads_1::thread_t 00042 { 00043 private : 00044 // Семафор, который необходим 00045 // для ожидания condition variable. 00046 const threads_1::mutex_sem_t & m_sem; 00047 00048 // Condition variable, срабатывание 00049 // которой ожидается нитью. 00050 const threads_1::cond_var_t & m_cv; 00051 public : 00052 type1_thread_t( 00053 const threads_1::mutex_sem_t & sem, 00054 const threads_1::cond_var_t & cv ); 00055 virtual ~type1_thread_t(); 00056 00057 protected : 00058 // Данный метод выполняет все действия нити. 00059 virtual void 00060 body(); 00061 }; 00062 00063 type1_thread_t::type1_thread_t( 00064 const threads_1::mutex_sem_t & sem, 00065 const threads_1::cond_var_t & cv ) 00066 : 00067 m_sem( sem ), 00068 m_cv( cv ) 00069 { 00070 } 00071 00072 type1_thread_t::~type1_thread_t() 00073 { 00074 } 00075 00076 void 00077 type1_thread_t::body() 00078 { 00079 std::cout << "Type1 thread started\n" << std::flush; 00080 00081 { 00082 // Захватываем mutex. 00083 threads_1::mutex_sem_t::lock_t lock( m_sem ); 00084 00085 // Ожидаем срабатывания condition variable. 00086 m_cv.wait( m_sem ); 00087 00088 // Condition variable сработала. 00089 // Если бы здесь выполнялись какие-то 00090 // операции над разделяемыми данными, то 00091 // этому бы никто не мешал, т.к. данная 00092 // нить владеет m_sem. 00093 std::cout << "Condition variable signaled\n" 00094 << std::flush; 00095 } 00096 00097 std::cout << "Type1 thread finished\n" << std::flush; 00098 } 00099 00100 /* 00101 Класс нити, которая: 00102 - засыпает на 1 секунду, 00103 - затем захватывает mutex1 и засыпает еще на 2 секунды, 00104 - затем порождает нотификацию, освобождает mutex1, 00105 - затем засыпает на 1 секунду, 00106 - захватывает mutex2, порождает нотификацию, 00107 - завершает свою работу. 00108 */ 00109 class type2_thread_t : 00110 public threads_1::thread_t 00111 { 00112 private : 00113 // Семафоры, который необходим 00114 // для ожидания condition variable. 00115 const threads_1::mutex_sem_t & m_sem1; 00116 const threads_1::mutex_sem_t & m_sem2; 00117 00118 // Condition variable, срабатывание 00119 // которой ожидается нитью. 00120 threads_1::cond_var_t & m_cv; 00121 public : 00122 type2_thread_t( 00123 const threads_1::mutex_sem_t & sem1, 00124 const threads_1::mutex_sem_t & sem2, 00125 threads_1::cond_var_t & cv ); 00126 virtual ~type2_thread_t(); 00127 00128 protected : 00129 // Данный метод выполняет все действия нити. 00130 virtual void 00131 body(); 00132 }; 00133 00134 type2_thread_t::type2_thread_t( 00135 const threads_1::mutex_sem_t & sem1, 00136 const threads_1::mutex_sem_t & sem2, 00137 threads_1::cond_var_t & cv ) 00138 : 00139 m_sem1( sem1 ), 00140 m_sem2( sem2 ), 00141 m_cv( cv ) 00142 { 00143 } 00144 00145 type2_thread_t::~type2_thread_t() 00146 { 00147 } 00148 00149 void 00150 type2_thread_t::body() 00151 { 00152 std::cout << "Type2 thread started\n" << std::flush; 00153 00154 { 00155 sleep( 1000 ); 00156 00157 { 00158 // Захватываем mutex. 00159 threads_1::mutex_sem_t::lock_t lock( m_sem1 ); 00160 std::cout << "Mutex locked #1" << std::endl; 00161 00162 sleep( 2000 ); 00163 std::cout << "Notification to all" << std::endl; 00164 m_cv.notify_all(); 00165 } 00166 00167 sleep( 1000 ); 00168 { 00169 // Захватываем mutex. 00170 threads_1::mutex_sem_t::lock_t lock( m_sem2 ); 00171 std::cout << "Mutex locked #2" << std::endl; 00172 std::cout << "Notification to all" << std::endl; 00173 m_cv.notify_all(); 00174 } 00175 } 00176 00177 std::cout << "Type2 thread finished\n" << std::flush; 00178 } 00179 00180 /* 00181 Класс нити, которая сначала засыпает на 2 секунды, 00182 затем ожидает наступления 00183 события (срабатывания condition variable), 00184 печатает на экран сообщение и завершается. 00185 00186 Данная нить должна завершить свою работу только после 00187 того, как нить типа 2 второй раз отошлет нотификацию. 00188 */ 00189 class type3_thread_t : 00190 public threads_1::thread_t 00191 { 00192 private : 00193 // Семафор, который необходим 00194 // для ожидания condition variable. 00195 const threads_1::mutex_sem_t & m_sem; 00196 00197 // Condition variable, срабатывание 00198 // которой ожидается нитью. 00199 const threads_1::cond_var_t & m_cv; 00200 public : 00201 type3_thread_t( 00202 const threads_1::mutex_sem_t & sem, 00203 const threads_1::cond_var_t & cv ); 00204 virtual ~type3_thread_t(); 00205 00206 protected : 00207 // Данный метод выполняет все действия нити. 00208 virtual void 00209 body(); 00210 }; 00211 00212 type3_thread_t::type3_thread_t( 00213 const threads_1::mutex_sem_t & sem, 00214 const threads_1::cond_var_t & cv ) 00215 : 00216 m_sem( sem ), 00217 m_cv( cv ) 00218 { 00219 } 00220 00221 type3_thread_t::~type3_thread_t() 00222 { 00223 } 00224 00225 void 00226 type3_thread_t::body() 00227 { 00228 std::cout << "Type3 thread started\n" << std::flush; 00229 00230 { 00231 sleep( 2000 ); 00232 00233 // Захватываем mutex. 00234 threads_1::mutex_sem_t::lock_t lock( m_sem ); 00235 00236 // Ожидаем срабатывания condition variable. 00237 m_cv.wait( m_sem ); 00238 00239 // Condition variable сработала. 00240 // Если бы здесь выполнялись какие-то 00241 // операции над разделяемыми данными, то 00242 // этому бы никто не мешал, т.к. данная 00243 // нить владеет m_sem. 00244 std::cout << "Condition variable signaled\n" 00245 << std::flush; 00246 } 00247 00248 sleep( 1000 ); 00249 std::cout << "Type3 thread finished\n" << std::flush; 00250 } 00251 00252 int 00253 main() 00254 { 00255 threads_1::mutex_sem_t sem1; 00256 threads_1::mutex_sem_t sem2; 00257 threads_1::cond_var_t cv; 00258 00259 type1_thread_t th1_1( sem1, cv ); 00260 type1_thread_t th1_2( sem1, cv ); 00261 type1_thread_t th1_3( sem1, cv ); 00262 type1_thread_t th1_4( sem1, cv ); 00263 type1_thread_t th1_5( sem1, cv ); 00264 type2_thread_t th2_1( sem1, sem2, cv ); 00265 type3_thread_t th3_1( sem2, cv ); 00266 type3_thread_t th3_2( sem2, cv ); 00267 type3_thread_t th3_3( sem2, cv ); 00268 type3_thread_t th3_4( sem2, cv ); 00269 type3_thread_t th3_5( sem2, cv ); 00270 00271 th1_1.start(); 00272 th1_2.start(); 00273 th1_3.start(); 00274 th1_4.start(); 00275 th1_5.start(); 00276 th2_1.start(); 00277 th3_1.start(); 00278 th3_2.start(); 00279 th3_3.start(); 00280 th3_4.start(); 00281 th3_5.start(); 00282 00283 th1_1.wait(); 00284 th1_2.wait(); 00285 th1_3.wait(); 00286 th1_4.wait(); 00287 th1_5.wait(); 00288 th2_1.wait(); 00289 th3_1.wait(); 00290 th3_2.wait(); 00291 th3_3.wait(); 00292 th3_4.wait(); 00293 th3_5.wait(); 00294 00295 return 0; 00296 }