/* 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(); // Condition variable сработала. // Если бы здесь выполнялись какие-то // операции над разделяемыми данными, то // этому бы никто не мешал, т.к. данная // нить владеет m_sem. std::cout << "Condition variable signaled\n" << std::flush; } std::cout << "Type1 thread finished\n" << std::flush; } /* Класс нити, которая: - засыпает на 1 секунду, - затем захватывает mutex и засыпает еще на 2 секунды, - затем порождает нотификацию, освобождает mutex, - затем засыпает на 1 секунду, - захватывает mutex, порождает нотификацию, - завершает свою работу. */ class type2_thread_t : public threads_1::thread_t { private : // Семафор, который необходим // для ожидания condition variable. const threads_1::mutex_sem_t & m_sem; // Condition variable, срабатывание // которой ожидается нитью. threads_1::cond_var_t & m_cv; public : type2_thread_t( const threads_1::mutex_sem_t & sem, 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 & sem, threads_1::cond_var_t & cv ) : m_sem( sem ), 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_sem ); 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_sem ); 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(); // 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 sem; threads_1::cond_var_t cv( sem ); type1_thread_t th1_1( sem, cv ); type1_thread_t th1_2( sem, cv ); type1_thread_t th1_3( sem, cv ); type1_thread_t th1_4( sem, cv ); type1_thread_t th1_5( sem, cv ); type2_thread_t th2_1( sem, cv ); type3_thread_t th3_1( sem, cv ); type3_thread_t th3_2( sem, cv ); type3_thread_t th3_3( sem, cv ); type3_thread_t th3_4( sem, cv ); type3_thread_t th3_5( sem, 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(); 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 - затем захватывает mutex и засыпает еще на 2 секунды, 00104 - затем порождает нотификацию, освобождает mutex, 00105 - затем засыпает на 1 секунду, 00106 - захватывает mutex, порождает нотификацию, 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_sem; 00116 00117 // Condition variable, срабатывание 00118 // которой ожидается нитью. 00119 threads_1::cond_var_t & m_cv; 00120 public : 00121 type2_thread_t( 00122 const threads_1::mutex_sem_t & sem, 00123 threads_1::cond_var_t & cv ); 00124 virtual ~type2_thread_t(); 00125 00126 protected : 00127 // Данный метод выполняет все действия нити. 00128 virtual void 00129 body(); 00130 }; 00131 00132 type2_thread_t::type2_thread_t( 00133 const threads_1::mutex_sem_t & sem, 00134 threads_1::cond_var_t & cv ) 00135 : 00136 m_sem( sem ), 00137 m_cv( cv ) 00138 { 00139 } 00140 00141 type2_thread_t::~type2_thread_t() 00142 { 00143 } 00144 00145 void 00146 type2_thread_t::body() 00147 { 00148 std::cout << "Type2 thread started\n" << std::flush; 00149 00150 { 00151 sleep( 1000 ); 00152 00153 { 00154 // Захватываем mutex. 00155 threads_1::mutex_sem_t::lock_t lock( m_sem ); 00156 std::cout << "Mutex locked #1" << std::endl; 00157 00158 sleep( 2000 ); 00159 std::cout << "Notification to all" << std::endl; 00160 m_cv.notify_all(); 00161 } 00162 00163 sleep( 1000 ); 00164 { 00165 // Захватываем mutex. 00166 threads_1::mutex_sem_t::lock_t lock( m_sem ); 00167 std::cout << "Mutex locked #2" << std::endl; 00168 std::cout << "Notification to all" << std::endl; 00169 m_cv.notify_all(); 00170 } 00171 } 00172 00173 std::cout << "Type2 thread finished\n" << std::flush; 00174 } 00175 00176 /* 00177 Класс нити, которая сначала засыпает на 2 секунды, 00178 затем ожидает наступления 00179 события (срабатывания condition variable), 00180 печатает на экран сообщение и завершается. 00181 00182 Данная нить должна завершить свою работу только после 00183 того, как нить типа 2 второй раз отошлет нотификацию. 00184 */ 00185 class type3_thread_t : 00186 public threads_1::thread_t 00187 { 00188 private : 00189 // Семафор, который необходим 00190 // для ожидания condition variable. 00191 const threads_1::mutex_sem_t & m_sem; 00192 00193 // Condition variable, срабатывание 00194 // которой ожидается нитью. 00195 const threads_1::cond_var_t & m_cv; 00196 public : 00197 type3_thread_t( 00198 const threads_1::mutex_sem_t & sem, 00199 const threads_1::cond_var_t & cv ); 00200 virtual ~type3_thread_t(); 00201 00202 protected : 00203 // Данный метод выполняет все действия нити. 00204 virtual void 00205 body(); 00206 }; 00207 00208 type3_thread_t::type3_thread_t( 00209 const threads_1::mutex_sem_t & sem, 00210 const threads_1::cond_var_t & cv ) 00211 : 00212 m_sem( sem ), 00213 m_cv( cv ) 00214 { 00215 } 00216 00217 type3_thread_t::~type3_thread_t() 00218 { 00219 } 00220 00221 void 00222 type3_thread_t::body() 00223 { 00224 std::cout << "Type3 thread started\n" << std::flush; 00225 00226 { 00227 sleep( 2000 ); 00228 00229 // Захватываем mutex. 00230 threads_1::mutex_sem_t::lock_t lock( m_sem ); 00231 00232 // Ожидаем срабатывания condition variable. 00233 m_cv.wait(); 00234 00235 // Condition variable сработала. 00236 // Если бы здесь выполнялись какие-то 00237 // операции над разделяемыми данными, то 00238 // этому бы никто не мешал, т.к. данная 00239 // нить владеет m_sem. 00240 std::cout << "Condition variable signaled\n" 00241 << std::flush; 00242 } 00243 00244 sleep( 1000 ); 00245 std::cout << "Type3 thread finished\n" << std::flush; 00246 } 00247 00248 int 00249 main() 00250 { 00251 threads_1::mutex_sem_t sem; 00252 threads_1::cond_var_t cv( sem ); 00253 00254 type1_thread_t th1_1( sem, cv ); 00255 type1_thread_t th1_2( sem, cv ); 00256 type1_thread_t th1_3( sem, cv ); 00257 type1_thread_t th1_4( sem, cv ); 00258 type1_thread_t th1_5( sem, cv ); 00259 type2_thread_t th2_1( sem, cv ); 00260 type3_thread_t th3_1( sem, cv ); 00261 type3_thread_t th3_2( sem, cv ); 00262 type3_thread_t th3_3( sem, cv ); 00263 type3_thread_t th3_4( sem, cv ); 00264 type3_thread_t th3_5( sem, cv ); 00265 00266 th1_1.start(); 00267 th1_2.start(); 00268 th1_3.start(); 00269 th1_4.start(); 00270 th1_5.start(); 00271 th2_1.start(); 00272 th3_1.start(); 00273 th3_2.start(); 00274 th3_3.start(); 00275 th3_4.start(); 00276 th3_5.start(); 00277 00278 th1_1.wait(); 00279 th1_2.wait(); 00280 th1_3.wait(); 00281 th1_4.wait(); 00282 th1_5.wait(); 00283 th2_1.wait(); 00284 th3_1.wait(); 00285 th3_2.wait(); 00286 th3_3.wait(); 00287 th3_4.wait(); 00288 th3_5.wait(); 00289 00290 return 0; 00291 }