Domanda

I'm trying to use pthreads with classes. I've read that the best solution to use threads with member functions is to define a static helper function and call the thread function from inside. But this requires a 'this' pointer to be passed as an argument to pthread_create. How do I implement this if my original thread function already has an argument? Is there a way to pass multiple arguments to pthread_create?

È stato utile?

Soluzione 2

You cannot pass multiple arguments to pthread_create, but you can pack multiple arguments into a struct that you create specifically for the purpose of packing the arguments. Make the struct "private" to your implementation by defining it in the cpp file, rather than in the header. Pass a pointer of that struct to pthread_create, then "unpack" it in the helper to call the member function.

Let's assume that the thread implementation is a member function threadRun defined as follows:

int MyClass::threadRun(int arg1, string arg2) {
    ...        // Do useful work
    return 42; // Return an important number
}

To call this function, define a thread_args struct like this:

struct thread_args {
    MyClass *instance;
    int arg1;
    string arg2;
};

Now your helper function can be defined as follows:

void* thread_helper(void *voidArgs) {
    thread_args *args = (thread_args*)voidArgs;
    int res = args->instance->threadRun(args->arg1, args->arg2);
    return new int(res); // Return an `int` pointer to pass back thread runner's results
}

The function that starts up the thread could look like this:

...
MyClass runner;
thread_args args;
args.instance = &runner;
args.arg1 = 123;
args.arg2 = "hello";
pthread_t thread_id;
int s = pthread_create(&thread_id, NULL, &thread_helper, &args);

Altri suggerimenti

pthread_create is defined as

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

So, it takes a function pointer, e.g.

void *myfunction(void *argument)

and the void* argument

If you want to use it in a class, do:

  1. Define a static method with the signature: static void *myMethod(void *argument)
  2. Call pthread_create from an object (non-static) method and pass this as the arg parameter.
  3. The implementation of the static method must cast the void *argument to a pointer of the class (a sort-of-this) that can be used to call other (non-static) methods of the object.

Now, depending of what other things you need to do in the thread and passing arguments to them, you can do several things:

  1. Instead of passing the this in the arg, pass a different type that can contain the this and all the arguments.
  2. Or, perhaps more OO, make those arguments, required by the thread functionaly, attributes of the class that can be set in the object before calling pthread_create and can be got from the sort-of-this

being more specific

class MyThread {
public:

   MyThread(int _argument): mArgument(_argument) { }

   void start() {
       pthread_create(&mThreadId, 0,&MyThreadClass::threadMethod, this);
   }

   void doThings(int x) {
       // something to be done in the thread.
   }

   static void *threadMethod(void *arg) {
       MyThread *_this=static_cast<MyThread *>(arg);
       _this->doThings(_this->getArgument());
   }

   int getArgument() const {
       return mArgument;
   }

private:
   pthread_t mThreadId;
   int mArgument;
};

That can be called as:

MyThread thread(10);
thread.start();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top