Re: Creating threads in C vs C++
On Jan 9, 7:08 pm, Rolf Magnus <ramag...@t-online.de> wrote:
James Kanze wrote:
You actually often need a double conversion when calling
pthread_create (and other, similar functions). Basically,
if you convert to void*, the only legal conversion is back
to the type you converted. And in the simplest case, you
will have just constructed a derived class (and have a
pointer to it), but will cast back to the base class, in
order to call a virtual function. So you need to ensure
that the pointer you convert to void* is a pointer to the
base class, not to the derived class.
The typical implementation that I know is based roughly on
something like that:
class Thread
{
public:
// ...
void run()
{
// ...
pthread_create(&tid, 0, thread_helper, this);
}
private:
virtual void doit() = 0;
pthread_t* tid;
};
extern "C"
void* thread_helper(void* arg)
{
static_cast<Thread*>(arg)->doit();
return arg;
}
Then you derive from Thread and implement the doit() function.
Doesn't get much simpler than that, and you get a conversion
from a Thread* to void* and back to Thread*.
That works. I'm not sure if it's really what I would consider
good design (although to be frank, I'm not sure what is good
design where threads are concerned); some would say that the
thread and the code it executes are logically two different
things. But just about anything which wraps the thread in a
class, and doesn't use templates, will do the trick. The
problem occurs either when calling pthread_create directly, or
when the thread class is a template (since the thread_helper
above can't be a template, so the template has to wrap in a
class using virtual functions)
BTW: When implementing something like that, I noticed that C++
lacks a way of defining functions with internal C linkage. I'd
usually make a function like thread_helper static (or, if it
were a C++ function, put it in an unnamed namespace), but I
have to make the linkage extern to make it a C function, and
there is no such thing as static "C" or extern "C" static.
I wouldn't swear to it, but I think:
extern "C" {
static void*
thread_helper(void* user_pointer)
{
static_cast< thread* >( user_pointer )->run();
return user_pointer;
}
}
would do the trick.
--
James Kanze