00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef THREADS_H
00026 #define THREADS_H
00027
00028 #include <errno.h>
00029 #include <cwidget/generic/util/exception.h>
00030
00031 namespace cwidget
00032 {
00038 namespace threads
00039 {
00041 class ThreadException : public util::Exception
00042 {
00043 };
00044
00049 class ThreadCreateException : public ThreadException
00050 {
00051 public:
00052 std::string errmsg() const;
00053 };
00054
00056 class ThreadJoinException : public ThreadException
00057 {
00058 std::string reason;
00059 public:
00060 ThreadJoinException(const int error);
00061
00062 std::string errmsg() const;
00063 };
00064
00070 class ConditionNotLockedException : public ThreadException
00071 {
00072 public:
00073 std::string errmsg() const;
00074 };
00075
00077 class DoubleLockException : public ThreadException
00078 {
00079 public:
00080 std::string errmsg() const;
00081 };
00082
00089 class thread
00090 {
00091 pthread_t tid;
00092 bool joined;
00093
00094 thread(const thread &other);
00095 thread &operator=(const thread &other);
00096
00097
00098
00099 template<typename F>
00100 static void *bootstrap(void *p)
00101 {
00102 F thunk(*((F *) p));
00103
00104 delete ((F *) p);
00105
00106 thunk();
00107
00108 return 0;
00109 }
00110
00111 public:
00120 class attr
00121 {
00122 pthread_attr_t attrs;
00123
00124 friend class thread;
00125 public:
00126 attr()
00127 {
00128 pthread_attr_init(&attrs);
00129 }
00130
00131
00132
00133
00134 void set_inherit_sched(int i)
00135 {
00136 pthread_attr_setinheritsched(&attrs, i);
00137 }
00138
00139 int get_inherit_sched() const
00140 {
00141 int rval;
00142 pthread_attr_getinheritsched(&attrs, &rval);
00143 return rval;
00144 }
00145
00146 void set_sched_param(const sched_param &sp)
00147 {
00148 pthread_attr_setschedparam(&attrs, &sp);
00149 }
00150
00151 sched_param get_sched_param() const
00152 {
00153 sched_param rval;
00154 pthread_attr_getschedparam(&attrs, &rval);
00155 return rval;
00156 }
00157
00158 void set_sched_policy(int p)
00159 {
00160 pthread_attr_setschedpolicy(&attrs, p);
00161 }
00162
00163 int get_sched_policy() const
00164 {
00165 int rval;
00166 pthread_attr_getschedpolicy(&attrs, &rval);
00167 return rval;
00168 }
00169
00170 void set_scope(int p)
00171 {
00172 pthread_attr_setscope(&attrs, p);
00173 }
00174
00175 int get_scope() const
00176 {
00177 int rval;
00178 pthread_attr_getscope(&attrs, &rval);
00179 return rval;
00180 }
00181
00182 ~attr()
00183 {
00184 pthread_attr_destroy(&attrs);
00185 }
00186 };
00187
00198 template<typename F>
00199 thread(const F &thunk, const attr &a = attr())
00200 :joined(false)
00201 {
00202
00203 F *tmp = new F(thunk);
00204
00205 if(pthread_create(&tid, &a.attrs, &thread::bootstrap<F>, tmp) != 0)
00206 {
00207 delete tmp;
00208
00209 throw ThreadCreateException();
00210 }
00211 }
00212
00213 ~thread()
00214 {
00215 if(!joined)
00216 pthread_detach(tid);
00217 }
00218
00220 void join()
00221 {
00222 int rval = pthread_join(tid, NULL);
00223
00224 if(rval != 0)
00225 throw ThreadJoinException(rval);
00226 else
00227 joined = true;
00228 }
00229
00231 void cancel()
00232 {
00233 pthread_cancel(tid);
00234 }
00235 };
00236
00249 template<typename F>
00250 struct noncopy_bootstrap
00251 {
00252 F &f;
00253 public:
00258 noncopy_bootstrap(F &_f)
00259 :f(_f)
00260 {
00261 }
00262
00264 void operator()()
00265 {
00266 f();
00267 }
00268 };
00269
00270 class condition;
00271
00272
00273 class mutex
00274 {
00275 public:
00276 class lock;
00277 class try_lock;
00278
00279 private:
00280 pthread_mutex_t m;
00281
00282 friend class lock;
00283 friend class try_lock;
00284
00285
00286
00287
00288 friend class condition;
00289
00290 mutex(const mutex &other);
00291 mutex &operator=(const mutex &other);
00292 public:
00294 class attr
00295 {
00296 pthread_mutexattr_t attrs;
00297
00298 friend class mutex;
00299
00300 public:
00301 attr()
00302 {
00303 pthread_mutexattr_init(&attrs);
00304 }
00305
00306 attr(int kind)
00307 {
00308 pthread_mutexattr_init(&attrs);
00309 pthread_mutexattr_settype(&attrs, kind);
00310 }
00311
00312 ~attr()
00313 {
00314 pthread_mutexattr_destroy(&attrs);
00315 }
00316
00317 int settype(int kind)
00318 {
00319 return pthread_mutexattr_settype(&attrs, kind);
00320 }
00321
00322 int gettype()
00323 {
00324 int rval;
00325 pthread_mutexattr_gettype(&attrs, &rval);
00326 return rval;
00327 }
00328 };
00329
00334 class lock
00335 {
00336 mutex &parent;
00337
00338 bool locked;
00339
00340 friend class condition;
00341
00342 lock(const lock &other);
00343 lock &operator=(const lock &other);
00344 public:
00345 lock(mutex &_parent)
00346 :parent(_parent), locked(false)
00347 {
00348 acquire();
00349 }
00350
00352 void acquire()
00353 {
00354 if(locked)
00355 throw DoubleLockException();
00356
00357 pthread_mutex_lock(&parent.m);
00358 locked = true;
00359 }
00360
00362 void release()
00363 {
00364 pthread_mutex_unlock(&parent.m);
00365 locked = false;
00366 }
00367
00368 bool get_locked() const
00369 {
00370 return locked;
00371 }
00372
00373 ~lock()
00374 {
00375 if(locked)
00376 pthread_mutex_unlock(&parent.m);
00377 }
00378 };
00379
00381 class try_lock
00382 {
00383 mutex &parent;
00384
00385 bool locked;
00386
00387 friend class condition;
00388
00389 try_lock(const try_lock &other);
00390 try_lock &operator=(const try_lock &other);
00391 public:
00392 try_lock(mutex &_parent)
00393 :parent(_parent)
00394 {
00395 acquire();
00396 }
00397
00398 ~try_lock()
00399 {
00400 if(locked)
00401 pthread_mutex_unlock(&parent.m);
00402 }
00403
00404 void acquire()
00405 {
00406 if(locked)
00407 throw DoubleLockException();
00408
00409 locked = pthread_mutex_trylock(&parent.m);
00410 }
00411
00412 void release()
00413 {
00414 pthread_mutex_unlock(&parent.m);
00415 locked = false;
00416 }
00417
00418 bool get_locked() const
00419 {
00420 return locked;
00421 }
00422 };
00423
00424 mutex()
00425 {
00426 pthread_mutex_init(&m, NULL);
00427 }
00428
00429 mutex(const attr &a)
00430 {
00431 pthread_mutex_init(&m, &a.attrs);
00432 }
00433
00434 ~mutex()
00435 {
00436 pthread_mutex_destroy(&m);
00437 }
00438 };
00439
00443 class recursive_mutex : public mutex
00444 {
00445 public:
00446 recursive_mutex()
00447 :mutex(attr(PTHREAD_MUTEX_RECURSIVE))
00448 {
00449 }
00450 };
00451
00456 class condition
00457 {
00458 pthread_cond_t cond;
00459 public:
00460 condition()
00461 {
00462 pthread_cond_init(&cond, NULL);
00463 }
00464
00465 ~condition()
00466 {
00467
00468 pthread_cond_broadcast(&cond);
00469 pthread_cond_destroy(&cond);
00470 }
00471
00472 void wake_one()
00473 {
00474 pthread_cond_signal(&cond);
00475 }
00476
00477 void wake_all()
00478 {
00479 pthread_cond_broadcast(&cond);
00480 }
00481
00485 template<typename Lock>
00486 void wait(const Lock &l)
00487 {
00488 if(!l.get_locked())
00489 throw ConditionNotLockedException();
00490
00491 pthread_cond_wait(&cond, &l.parent.m);
00492 }
00493
00495 template<typename Lock, typename Pred>
00496 void wait(const Lock &l, Pred p)
00497 {
00498 if(!l.get_locked())
00499 throw ConditionNotLockedException();
00500
00501 while(!p())
00502 wait(l);
00503 }
00504
00514 template<typename Lock>
00515 bool timed_wait(const Lock &l, const timespec &until)
00516 {
00517 if(!l.get_locked())
00518 throw ConditionNotLockedException();
00519
00520 int rval;
00521
00522
00523 while((rval = pthread_cond_timedwait(&cond, &l.parent.m, &until)) == EINTR)
00524 ;
00525
00526 return rval != ETIMEDOUT;
00527 }
00528
00532 template<typename Lock, typename Pred>
00533 bool timed_wait(const Lock &l, const timespec &until, const Pred &p)
00534 {
00535 if(!l.get_locked())
00536 throw ConditionNotLockedException();
00537
00538 while(!p())
00539 {
00540 if(!timed_wait(l, until))
00541 return false;
00542 }
00543
00544 return true;
00545 }
00546 };
00547
00559 template<typename T>
00560 class box
00561 {
00562 T val;
00563 bool filled;
00564
00565 condition cond;
00566 mutex m;
00567
00568 box(const box &other);
00569 box &operator=(const box &other);
00570 public:
00572 box()
00573 :filled(false)
00574 {
00575 }
00576
00578 box(const T &_val)
00579 :val(_val), filled(true)
00580 {
00581 }
00582
00586 T take();
00587
00591 void put(const T &t);
00592
00599 bool try_take(T &out);
00600
00609 bool try_put(const T &t);
00610
00614 bool timed_take(T &out, const timespec &until);
00615
00619 bool timed_put(const T &t, const timespec &until);
00620
00625 template<typename Mutator>
00626 void update(const Mutator &m);
00627 };
00628
00633 template<>
00634 class box<void>
00635 {
00636 bool filled;
00637 mutex m;
00638 condition cond;
00639 public:
00640 box()
00641 :filled(false)
00642 {
00643 }
00644
00645 box(bool _filled)
00646 :filled(_filled)
00647 {
00648 }
00649
00650 void take();
00651
00652 void put();
00653
00654 bool try_take();
00655 bool try_put();
00656
00657 bool timed_take(const timespec &until);
00658 bool timed_put(const timespec &until);
00659
00660 template<typename Mutator>
00661 void update(const Mutator &m)
00662 {
00663 take();
00664 try
00665 {
00666 m();
00667 }
00668 catch(...)
00669 {
00670 put();
00671 throw;
00672 }
00673
00674 put();
00675 }
00676 };
00677
00679 struct bool_ref_pred
00680 {
00681 const bool &b;
00682 public:
00683 bool_ref_pred(const bool &_b)
00684 :b(_b)
00685 {
00686 }
00687
00688 bool operator()() const
00689 {
00690 return b;
00691 }
00692 };
00693
00695 struct not_bool_ref_pred
00696 {
00697 const bool &b;
00698 public:
00699 not_bool_ref_pred(const bool &_b)
00700 :b(_b)
00701 {
00702 }
00703
00704 bool operator()() const
00705 {
00706 return !b;
00707 }
00708 };
00709
00710 template<typename T>
00711 inline
00712 T box<T>::take()
00713 {
00714 mutex::lock l(m);
00715
00716 cond.wait(l, bool_ref_pred(filled));
00717
00718 filled = false;
00719
00720
00721
00722 T rval = val;
00723 return rval;
00724 }
00725
00726 inline
00727 void box<void>::take()
00728 {
00729 mutex::lock l(m);
00730 cond.wait(l, bool_ref_pred(filled));
00731 filled = false;
00732 }
00733
00734 template<typename T>
00735 inline
00736 bool box<T>::try_take(T &out)
00737 {
00738 mutex::lock l(m);
00739
00740 if(filled)
00741 {
00742 filled = false;
00743 out = val;
00744 return true;
00745 }
00746 else
00747 return false;
00748 }
00749
00750 inline
00751 bool box<void>::try_take()
00752 {
00753 mutex::lock l(m);
00754
00755 if(filled)
00756 {
00757 filled = false;
00758 return true;
00759 }
00760 else
00761 return false;
00762 }
00763
00764 template<typename T>
00765 inline
00766 bool box<T>::timed_take(T &out, const timespec &until)
00767 {
00768 mutex::lock l(m);
00769
00770 if(cond.timed_wait(l, until, bool_ref_pred(filled)))
00771 {
00772 filled = false;
00773 out = val;
00774 return true;
00775 }
00776 else
00777 return false;
00778 }
00779
00780 inline
00781 bool box<void>::timed_take(const timespec &until)
00782 {
00783 mutex::lock l(m);
00784
00785 if(cond.timed_wait(l, until, bool_ref_pred(filled)))
00786 {
00787 filled = false;
00788 return true;
00789 }
00790 else
00791 return false;
00792 }
00793
00794 template<typename T>
00795 inline
00796 void box<T>::put(const T &new_val)
00797 {
00798 mutex::lock l(m);
00799
00800 cond.wait(l, not_bool_ref_pred(filled));
00801
00802 filled = true;
00803 val = new_val;
00804 cond.wake_one();
00805 }
00806
00807 inline
00808 void box<void>::put()
00809 {
00810 mutex::lock l(m);
00811
00812 cond.wait(l, not_bool_ref_pred(filled));
00813
00814 filled = true;
00815 cond.wake_one();
00816 }
00817
00818 template<typename T>
00819 inline
00820 bool box<T>::try_put(const T &new_val)
00821 {
00822 mutex::lock l(m);
00823
00824 if(!filled)
00825 {
00826 filled = true;
00827 val = new_val;
00828 cond.wake_one();
00829 return true;
00830 }
00831 else
00832 return false;
00833 }
00834
00835 inline
00836 bool box<void>::try_put()
00837 {
00838 mutex::lock l(m);
00839
00840 if(!filled)
00841 {
00842 filled = true;
00843 cond.wake_one();
00844 return true;
00845 }
00846 else
00847 return false;
00848 }
00849
00850 template<typename T>
00851 inline
00852 bool box<T>::timed_put(const T &new_val, const timespec &until)
00853 {
00854 mutex::lock l(m);
00855
00856 if(cond.timed_wait(l, until, not_bool_ref_pred(filled)))
00857 {
00858 filled = true;
00859 val = new_val;
00860 cond.wake_one();
00861 return true;
00862 }
00863 else
00864 return false;
00865 }
00866
00867 inline
00868 bool box<void>::timed_put(const timespec &until)
00869 {
00870 mutex::lock l(m);
00871
00872 if(cond.timed_wait(l, until, not_bool_ref_pred(filled)))
00873 {
00874 filled = true;
00875 cond.wake_one();
00876 return true;
00877 }
00878 else
00879 return false;
00880 }
00881
00882 template<typename T>
00883 template<typename Mutator>
00884 inline
00885 void box<T>::update(const Mutator &m)
00886 {
00887 mutex::lock l(m);
00888
00889 cond.wait(l, bool_ref_pred(filled));
00890
00891 T new_val = m(val);
00892
00893 val = new_val;
00894 cond.wake_one();
00895 }
00896
00897
00898
00899
00900 template<typename T>
00901 class ptr_box
00902 {
00903 box<T *> b;
00904 public:
00905 ptr_box()
00906 {
00907 }
00908
00909 ptr_box(const T *val)
00910 :b(val)
00911 {
00912 }
00913
00914 ~ptr_box()
00915 {
00916 T *x;
00917
00918 if(b.try_get(x))
00919 delete x;
00920 }
00921
00922 T *take()
00923 {
00924 return b.take();
00925 }
00926
00927 bool try_take(const T * &out)
00928 {
00929 return b.try_take(out);
00930 }
00931
00932 bool timed_take(const T * &out, const timespec &until)
00933 {
00934 return b.timed_take(out);
00935 }
00936
00937 void put(const T *in)
00938 {
00939 b.put(in);
00940 }
00941
00942 bool try_put(const T *in)
00943 {
00944 return b.try_put(in);
00945 }
00946
00947 bool timed_put(const T *in, const timespec &until)
00948 {
00949 return b.timed_put(in, until);
00950 }
00951 };
00952
00953
00954
00955
00956
00957 template<typename F>
00958 class bootstrap_proxy
00959 {
00960 F *f;
00961 public:
00962 bootstrap_proxy(F *_f)
00963 : f(_f)
00964 {
00965 }
00966
00967 void operator()() const
00968 {
00969 (*f)();
00970 }
00971 };
00972
00973 template<typename F>
00974 bootstrap_proxy<F> make_bootstrap_proxy(F *f)
00975 {
00976 return bootstrap_proxy<F>(f);
00977 }
00978 }
00979 }
00980
00981 #endif // THREADS_H
00982