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
00488 template<typename Lock>
00489 void wait(const Lock &l)
00490 {
00491 if(!l.get_locked())
00492 throw ConditionNotLockedException();
00493
00494 pthread_cleanup_push((void (*)(void*))pthread_mutex_unlock, &l.parent.m);
00495 pthread_cond_wait(&cond, &l.parent.m);
00496 pthread_cleanup_pop(0);
00497 }
00498
00507 template<typename Lock, typename Pred>
00508 void wait(const Lock &l, Pred p)
00509 {
00510 if(!l.get_locked())
00511 throw ConditionNotLockedException();
00512
00513 while(!p())
00514 wait(l);
00515 }
00516
00532 template<typename Lock>
00533 bool timed_wait(const Lock &l, const timespec &until)
00534 {
00535 if(!l.get_locked())
00536 throw ConditionNotLockedException();
00537
00538 int rval;
00539
00540 pthread_cleanup_push((void(*)(void *))&pthread_mutex_unlock, &l.parent.m);
00541 while((rval = pthread_cond_timedwait(&cond, &l.parent.m, &until)) == EINTR)
00542 ;
00543 pthread_cleanup_pop(0);
00544
00545 return rval != ETIMEDOUT;
00546 }
00547
00558 template<typename Lock, typename Pred>
00559 bool timed_wait(const Lock &l, const timespec &until, const Pred &p)
00560 {
00561 if(!l.get_locked())
00562 throw ConditionNotLockedException();
00563
00564 while(!p())
00565 {
00566 if(!timed_wait(l, until))
00567 return false;
00568 }
00569
00570 return true;
00571 }
00572 };
00573
00585 template<typename T>
00586 class box
00587 {
00588 T val;
00589 bool filled;
00590
00591 condition cond;
00592 mutex m;
00593
00594 box(const box &other);
00595 box &operator=(const box &other);
00596 public:
00598 box()
00599 :filled(false)
00600 {
00601 }
00602
00604 box(const T &_val)
00605 :val(_val), filled(true)
00606 {
00607 }
00608
00612 T take();
00613
00617 void put(const T &t);
00618
00625 bool try_take(T &out);
00626
00635 bool try_put(const T &t);
00636
00640 bool timed_take(T &out, const timespec &until);
00641
00645 bool timed_put(const T &t, const timespec &until);
00646
00651 template<typename Mutator>
00652 void update(const Mutator &m);
00653 };
00654
00659 template<>
00660 class box<void>
00661 {
00662 bool filled;
00663 mutex m;
00664 condition cond;
00665 public:
00666 box()
00667 :filled(false)
00668 {
00669 }
00670
00671 box(bool _filled)
00672 :filled(_filled)
00673 {
00674 }
00675
00676 void take();
00677
00678 void put();
00679
00680 bool try_take();
00681 bool try_put();
00682
00683 bool timed_take(const timespec &until);
00684 bool timed_put(const timespec &until);
00685
00686 template<typename Mutator>
00687 void update(const Mutator &m)
00688 {
00689 take();
00690 try
00691 {
00692 m();
00693 }
00694 catch(...)
00695 {
00696 put();
00697 throw;
00698 }
00699
00700 put();
00701 }
00702 };
00703
00705 struct bool_ref_pred
00706 {
00707 const bool &b;
00708 public:
00709 bool_ref_pred(const bool &_b)
00710 :b(_b)
00711 {
00712 }
00713
00714 bool operator()() const
00715 {
00716 return b;
00717 }
00718 };
00719
00721 struct not_bool_ref_pred
00722 {
00723 const bool &b;
00724 public:
00725 not_bool_ref_pred(const bool &_b)
00726 :b(_b)
00727 {
00728 }
00729
00730 bool operator()() const
00731 {
00732 return !b;
00733 }
00734 };
00735
00736 template<typename T>
00737 inline
00738 T box<T>::take()
00739 {
00740 mutex::lock l(m);
00741
00742 cond.wait(l, bool_ref_pred(filled));
00743
00744 filled = false;
00745
00746
00747
00748 T rval = val;
00749 return rval;
00750 }
00751
00752 inline
00753 void box<void>::take()
00754 {
00755 mutex::lock l(m);
00756 cond.wait(l, bool_ref_pred(filled));
00757 filled = false;
00758 }
00759
00760 template<typename T>
00761 inline
00762 bool box<T>::try_take(T &out)
00763 {
00764 mutex::lock l(m);
00765
00766 if(filled)
00767 {
00768 filled = false;
00769 out = val;
00770 return true;
00771 }
00772 else
00773 return false;
00774 }
00775
00776 inline
00777 bool box<void>::try_take()
00778 {
00779 mutex::lock l(m);
00780
00781 if(filled)
00782 {
00783 filled = false;
00784 return true;
00785 }
00786 else
00787 return false;
00788 }
00789
00790 template<typename T>
00791 inline
00792 bool box<T>::timed_take(T &out, const timespec &until)
00793 {
00794 mutex::lock l(m);
00795
00796 if(cond.timed_wait(l, until, bool_ref_pred(filled)))
00797 {
00798 filled = false;
00799 out = val;
00800 return true;
00801 }
00802 else
00803 return false;
00804 }
00805
00806 inline
00807 bool box<void>::timed_take(const timespec &until)
00808 {
00809 mutex::lock l(m);
00810
00811 if(cond.timed_wait(l, until, bool_ref_pred(filled)))
00812 {
00813 filled = false;
00814 return true;
00815 }
00816 else
00817 return false;
00818 }
00819
00820 template<typename T>
00821 inline
00822 void box<T>::put(const T &new_val)
00823 {
00824 mutex::lock l(m);
00825
00826 cond.wait(l, not_bool_ref_pred(filled));
00827
00828 filled = true;
00829 val = new_val;
00830 cond.wake_one();
00831 }
00832
00833 inline
00834 void box<void>::put()
00835 {
00836 mutex::lock l(m);
00837
00838 cond.wait(l, not_bool_ref_pred(filled));
00839
00840 filled = true;
00841 cond.wake_one();
00842 }
00843
00844 template<typename T>
00845 inline
00846 bool box<T>::try_put(const T &new_val)
00847 {
00848 mutex::lock l(m);
00849
00850 if(!filled)
00851 {
00852 filled = true;
00853 val = new_val;
00854 cond.wake_one();
00855 return true;
00856 }
00857 else
00858 return false;
00859 }
00860
00861 inline
00862 bool box<void>::try_put()
00863 {
00864 mutex::lock l(m);
00865
00866 if(!filled)
00867 {
00868 filled = true;
00869 cond.wake_one();
00870 return true;
00871 }
00872 else
00873 return false;
00874 }
00875
00876 template<typename T>
00877 inline
00878 bool box<T>::timed_put(const T &new_val, const timespec &until)
00879 {
00880 mutex::lock l(m);
00881
00882 if(cond.timed_wait(l, until, not_bool_ref_pred(filled)))
00883 {
00884 filled = true;
00885 val = new_val;
00886 cond.wake_one();
00887 return true;
00888 }
00889 else
00890 return false;
00891 }
00892
00893 inline
00894 bool box<void>::timed_put(const timespec &until)
00895 {
00896 mutex::lock l(m);
00897
00898 if(cond.timed_wait(l, until, not_bool_ref_pred(filled)))
00899 {
00900 filled = true;
00901 cond.wake_one();
00902 return true;
00903 }
00904 else
00905 return false;
00906 }
00907
00908 template<typename T>
00909 template<typename Mutator>
00910 inline
00911 void box<T>::update(const Mutator &m)
00912 {
00913 mutex::lock l(m);
00914
00915 cond.wait(l, bool_ref_pred(filled));
00916
00917 T new_val = m(val);
00918
00919 val = new_val;
00920 cond.wake_one();
00921 }
00922
00923
00924
00925
00926 template<typename T>
00927 class ptr_box
00928 {
00929 box<T *> b;
00930 public:
00931 ptr_box()
00932 {
00933 }
00934
00935 ptr_box(const T *val)
00936 :b(val)
00937 {
00938 }
00939
00940 ~ptr_box()
00941 {
00942 T *x;
00943
00944 if(b.try_get(x))
00945 delete x;
00946 }
00947
00948 T *take()
00949 {
00950 return b.take();
00951 }
00952
00953 bool try_take(const T * &out)
00954 {
00955 return b.try_take(out);
00956 }
00957
00958 bool timed_take(const T * &out, const timespec &until)
00959 {
00960 return b.timed_take(out);
00961 }
00962
00963 void put(const T *in)
00964 {
00965 b.put(in);
00966 }
00967
00968 bool try_put(const T *in)
00969 {
00970 return b.try_put(in);
00971 }
00972
00973 bool timed_put(const T *in, const timespec &until)
00974 {
00975 return b.timed_put(in, until);
00976 }
00977 };
00978
00979
00980
00981
00982
00983 template<typename F>
00984 class bootstrap_proxy
00985 {
00986 F *f;
00987 public:
00988 bootstrap_proxy(F *_f)
00989 : f(_f)
00990 {
00991 }
00992
00993 void operator()() const
00994 {
00995 (*f)();
00996 }
00997 };
00998
00999 template<typename F>
01000 bootstrap_proxy<F> make_bootstrap_proxy(F *f)
01001 {
01002 return bootstrap_proxy<F>(f);
01003 }
01004 }
01005 }
01006
01007 #endif // THREADS_H
01008