Boost logo

Boost :

From: MaximE (maxim.yegorushkin_at_[hidden])
Date: 2006-04-09 15:21:16


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));
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk