|
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