
In my home grown POSIX threads wrapper I use expression templates to specify thread, mutex, condition attributes with the following syntax: mutex m(shared | recursive); thread t(..., detached | sched_policy(SCHED_FIFO) | sched_priority(1)); I thought it might be appealing for boost threads library to have something similar. Sketch code follows. #include <pthread.h> #include <memory> // sinposis class error; class thread; template<class T> struct concept; template<class left, class right> struct binary_op; template<class left, class right> binary_op<left, right> operator|(concept<left> const& l, concept<right> const& r); struct detached; struct sched_policy; struct sched_priority; class error : public std::exception { private: char const* s_; int c_; public: error(int code) : s_("thread::error"), c_(code) {} error(char const* s, int c) : s_(s), c_(c) {} int code() const { return c_; } char const* what() const throw() { return s_; } }; #define THREAD_CHK_CALL(call) \ do { \ if(int __thread_error_code__ = (call)) \ throw ::error(#call, __thread_error_code__); \ } while(0) template<class T> struct concept { T const& self() const { return static_cast<T const&>(*this); } }; template<class left, class right> struct binary_op : concept<binary_op<left, right> > { left const& l_; right const& r_; binary_op(left const& l, right const& r) : l_(l), r_(r) {} void apply(pthread_attr_t* a) const { l_.apply(a); r_.apply(a); } }; template<class left, class right> inline binary_op<left, right> operator|(concept<left> const& l, concept<right> const& r) { return binary_op<left, right>(l.self(), r.self()); } struct detached : concept<detached> { detached() {} static void apply(pthread_attr_t* a) { THREAD_CHK_CALL(::pthread_attr_setdetachstate(a, PTHREAD_CREATE_DETACHED)); } } const detached; struct sched_policy : concept<sched_policy> { int policy_; sched_policy(int p) : policy_(p) {} void apply(pthread_attr_t* a) const { THREAD_CHK_CALL(::pthread_attr_setschedpolicy(a, policy_)); } }; struct sched_priority : concept<sched_priority> { int priority_; sched_priority(int p) : priority_(p) {} void apply(pthread_attr_t* a) const { sched_param p; p.sched_priority = priority_; THREAD_CHK_CALL(::pthread_attr_setschedparam(a, &p)); } }; class thread { private: pthread_t id_; unsigned joinable_ : 1; private: // noncopyable thread(thread const&); thread& operator=(thread const&); private: struct scoped_attr { pthread_attr_t a; scoped_attr() { THREAD_CHK_CALL(::pthread_attr_init(&a)); } ~scoped_attr() { ::pthread_attr_destroy(&a); } }; private: template<class functor> void start(functor const& f, pthread_attr_t const* a) { struct t // trampoline { static void* f(void* a) { // copy the functor and free the allocated memory before // executing the functor std::auto_ptr<functor> f(static_cast<functor*>(a)); functor e(*f); f.release(); return e(); } }; std::auto_ptr<functor> e(new functor(f)); THREAD_CHK_CALL(::pthread_create(&id_, a, &t::f, e.get())); e.release(); } void start(void*(*fun)(void*), void* arg, pthread_attr_t const* a) { THREAD_CHK_CALL(::pthread_create(&id_, a, fun, arg)); } public: thread() : id_(::pthread_self()), joinable_(1) {} thread(void*(*fun)(void*), void* arg) : joinable_(1) { this->start(fun, arg, 0); } template<class functor> thread(functor const& f) : joinable_(1) { this->start(f, 0); } template<class A> thread(void*(*fun)(void*), void* arg, concept<A> const& attr) { scoped_attr a; attr.self().apply(&a.a); int j; THREAD_CHK_CALL(::pthread_attr_getdetachstate(&a.a, &j)); joinable_ = PTHREAD_CREATE_JOINABLE == j; this->start(fun, arg, &a.a); } template<class functor, class A> thread(functor const& f, concept<A> const& attr) { scoped_attr a; attr.self().apply(&a.a); int j; THREAD_CHK_CALL(::pthread_attr_getdetachstate(&a.a, &j)); joinable_ = PTHREAD_CREATE_JOINABLE == j; this->start(f, &a.a); } ~thread() { if(joinable_) ::pthread_detach(id_); } void* join() { if(!joinable_) throw error("thread::join()", 0); void* p; THREAD_CHK_CALL(::pthread_join(id_, &p)); joinable_ = 0; return p; } }; void* f(void*) { return 0; } int main() { thread t(f, 0, detached | sched_policy(SCHED_FIFO) | sched_priority(1)); }
participants (1)
-
MaximE