LB is correct -- multiple threads touching the same object is dangerous. Be sure that this is really the best way to approach this problem. Thread synchronization is something that has to be considered and planned out before you write a single line of code -- it is extremely difficult to squeeze it in as an afterthought. Trying to do so will undoubtedly result in numerous hard to find bugs (and maybe even extremely poor performance)
That said there
are some legitimate use cases where you'd want to do this. Assuming this is such a case:
As mentioned, C++11 threads make this trivial. Considering the standard is 4 years old now and all major compilers have supported it for quite some time, there's isn't much reason why you shouldn't be using it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
class Foo
{
typedef std::unique_ptr<std::thread> ThreadPtr;
ThreadPtr launcher()
{
return ThreadPtr( new std::thread(
std::bind( &Foo::task, this, param1, param2, param3 )
) );
}
int task(int param1, int param2, int param3)
{
//...
}
};
|
With pthreads, since you can't use a functor object (it only gives you a void pointer to pass as user data), you'll have to have some other object (like a struct) which houses all the data you want to pass in. Then you can pass a pointer to that house as the void* user data.
The bigger problem is ownership of the house. The launcher has to create it, but it can't release it until the task has used it. So the launcher effectively has to pass ownership to the task. This is trickier than it sounds.
You
could synchronize with a mutex and have the launcher wait until the task notifies that it has taken ownership, but that is complicated and slow.
What you
can't do, is have a simple stack-allocated object in the launcher and just pass it to the task normally... as there is no guarantee that the task will use that object before the launcher's stack unwinds and destroys it.
What I would do is... (well actually I would use C++11 threads ... but if you were to tie my hands and say I couldn't for some reason...) I would dynamically allocate the house in the launcher, and maintain ownership until pthreads verifies the thread has started, then release ownership and let the task be responsible for deleting it.
But again this is clumsy and extremely easy to get wrong. There's a lot of nuance to it and it's a maintenance nightmare. You really should just use C++11 threads.
Here's my first stab at it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
// note: I don't know pthread details. I'm going to assume there's a pthread_create function
// and that it returns a pointer to the generated 'pthread_t' object, or null if the thread
// failed to create
class Foo
{
struct House
{
Foo* obj;
int param1;
int param2;
int param3;
};
typedef std::unique_ptr<House> HousePtr;
pthread_t* launcher()
{
HousePtr house(new House);
house->obj = this;
house->param1 = foo;
house->param2 = bar;
house->param3 = baz;
pthread_t* thd = pthread_create( &Foo::callTask, house.get() );
if(thd) // if thread created successfully
{
house.release(); // <- release ownership (but don't delete!) the object
// The child thread now owns it
}
return thd;
}
static int callTask(void* voidHouse)
{
HousePtr house( reinterpret_cast<House*>(voidHouse) ); // <- take ownership of the object
return house->obj->task( house->param1, house->param2, house->param3 );
}
int task( int param1, int param2, int param3 )
{
//...
}
};
|
You could make the house a class member, which would greatly simplify this... but then your launcher would only be good for generating exactly 1 thread. You wouldn't be able to call it multiple times to generate multiple threads.
EDIT:
FWIW I made an [untested] thread pool class for another forum post that might be a helpful reference for C++11 threads:
http://www.cplusplus.com/forum/general/159379/#msg813869