tags:

views:

3133

answers:

7

I'm wondering the best way to start a pthread that is a member of a C++ class? My own approach follows as an answer...

A: 

So, I usually declare a friend function and have that call a public method that does what I want the thread to accomplish. Is this the best design practice, or should I be doing something else? Thx

jdt141
A: 

Sorry for the obligatory comment, but have you considered using Boost instead?

Matt Cruikshank
+10  A: 

I usually use a static member function of the class, and use a pointer to the class as the void * parameter. That function can then either perform thread processing, or call another non-static member function with the class reference. That function can then reference all class members without awkward syntax.

shmuelp
The wrapper function should have C linkage. Function pointers of free functions might be incompatible due to language linkage
sellibitze
+7  A: 
Adam Rosenfield
+10  A: 

This can be simply done by pulling a couple things from the boost libraries, like this:

#include <boost/function.hpp>
#include <boost/thread.hpp>

class cMyClass
{
public:
void Run();
}

cMyClass theClass;

// start new thread by invoking method run on theClass instance

boost::thread* pThread = new boost::thread(
    boost::bind( 
    &cMyClass::Run,  // member function
    &theClass ) );  // instance of class

Notes:

  • This uses an ordinary class member function. There is no need to add extra, static members which confuse your class interface
  • Just include boost/function.hpp and boost/thread.hpp in the source file where you start the thread. If you are just starting with boost, all the rest of that large and intimidating package can be ignored.
ravenspoint
So, I'm not opposed to this... but noone in the shop I work at uses boost... it would be a big paradigm shift. Its a rather huge library as well... what's the best way to start to introduce using it??
jdt141
Well, it isn't actually a library at all, just a bunch of includes. So you can pick out some small part of it that catches your fancy and start by including those headers where you need them. Just a couple of neat new language features that you can user here and there as seems appropriate.
ravenspoint
+1  A: 

I have used three of the methods outlined above. When I first used threading in c++ I used static member functions, then friend functions and finally the BOOST libraries. Currently I prefer BOOST. Over the past several years I've become quite the BOOST bigot.

BOOST is to C++ as CPAN is to Perl. :)

Thanatopsis
A: 

The boost library provides a copy mechanism, which helps to transfer object information to the new thread. In the other boost example boost::bind will be copied with a pointer, which is also just copied. So you'll have to take care for the validity of your object to prevent a dangling pointer. If you implement the operator() and provide a copy constructor instead and pass the object directly, you don't have to care about it.

A much nicer solution, which prevents a lot of trouble:

#include <boost/thread.hpp>

class MyClass {
public:
        MyClass(int i);
        MyClass(const MyClass& myClass);  // Copy-Constructor
        void operator()() const;          // entry point for the new thread

        virtual void doSomething();       // Now you can use virtual functions

private:
        int i;                            // and also fields very easily
};

MyClass clazz(1);
// Passing the object directly will create a copy internally
// Now you don't have to worry about the validity of the clazz object above
// after starting the other thread
// The operator() will be executed for the new thread.
boost::thread thread(clazz);             // create the object on the stack

The other boost example creates the thread object on the heap, although there is no sense to do it.

CSpille
What happens if there are two or more different methods in the class that you need to run? Using the () operator is clever ( nice? ) but is it the best way, given that you can only have one per class?
ravenspoint
Another thought: insisting on copying the class every time the method is started may not be the best way if the class copy is expensive ( e.g. requires lots of memory ) or may even break the design if the class is a singleton. In any case, what is happening will have to be documented carefully since a lot more is going on than simply running a method.
ravenspoint
It's a nice idea to wrap a mechanism, which allows you to call several functions on a class, but you'll rarely need it. First I thought it's a nice way, but then I noticed the side effects. If you'd implement something with a copy mechanism, I'd like it. Passing the object instead of the pointer to the boost::bind will copy the object several times. But otherwise you will get trouble in most cases, except Singletons and some 'crazy' object management
CSpille
If you're talking about designing a program, you should consider, that a singleton shouldn't have a copy constructor, so you'll notice it at compile time.Of course you have to take 'care' of the complexity of a copy. If necessary, you might use smart pointers inside this your object referencing complex structures. The other posted example is completely restricted on the execution of a singleton function (or crazy object management). In this case boost::bind is nice, but hides trouble else. You can't (easily) create a dynamic number of threads with different objects using the other example.
CSpille
@CSpille Are you aware of the dangers of using pointers to reference class data? It does decrease the time and space needs of the default copy constructor, but leaves the copy and the original sharing the same data. If the data is modified by one, it also modifies the other. Not only is this probably not the design intent, but it leads to horrible race conditions between the threads!!!
ravenspoint
@ravenspoint: You have an object, which the original and the new thread is using and also contains the logic for running the new tread including parameters? Please redesign your classes!!! If you want to share data between two threads, you can pass a pointer to your the object, which contains the data. If two threads are working on the same data, you will of course need a logic, when the data is not needed anymore. But I think you don't understand the problem. How do you want to create n threads with the parameters 0 to n-1 with your approach? You can't pass any thread-specific data!!!
CSpille
@ravenspoint: If you want to create the object on the heap now and delete it after execution in an other thread, I should probably remind you of RAII -> very bad programming style!!! Or do you want to make some silly synchronisation to ensure the data is still valid, when being read by the new thread?
CSpille
@ravenspoint: YES, I'm aware of the dangers of using pointers to reference class data, but I'm not sure, if you know, how you handle your objects and memory. I think, you don't have to explain me something concerning memory management and pointers, as long as you can't tell me a reason for creating the boost::thread on the heap. Even if you posted only a 'code fragment', it looks much like two sequenced commands. They don't work inside a function and now you want to defend them as singleton. Or should both commands be outside a function? There is no order for initialising static variables!
CSpille
@CSpille In the code fragment I posted the thread object is created on the heap. As you pointed out, if the programmer forgets to delete it, there will be a memory leak.
ravenspoint
@CSpille In your code fragment, you make a copy of the entire class every time a method is invoked. I doubt that this is always the best way. For example, in my work simulating particle flows, I deal with classes that contain hundreds of thousands of objects and so I have to be careful that there are no unexpected calls to the copy constructor. The program runs many times faster if the data for each thread is copied just once, then the class methods can be invoked on the copy that 'belongs' to that thread.
ravenspoint
@ravenpoint: Even if you delete it, the creation of the thread object on the heap doesn't make sense. In your case, I'd create a class containing a (smart) pointer to the thread class info. I'm copying the MyClass object once per starting a thread. But where do you copy it? In your case, is cMyClass theClass a singleton object or an object on the stack? In both cases, you are running two threads exactly on the same data (with the same context), as the pointer address is equal executing the code several times. Or do you call something recursively to ensure the stack data not being replaced?
CSpille