3

I am creating a data-parallel program using pthreads and C++. From pthread function from a class, I found out how to supply pthread_create with a function pointer to a static C++ function(and supply it a this argument).

However, I also need to supply the thread with an index, so it knows what data it's working on. I could malloc a struct for each thread(with both the pointer to the C++ class and an index), but this seems like it would add some bookkeeping code, and could lead to leaks if the struct isn't freed. Is there a better way to do this?

Community
  • 1
  • 1
Mike
  • 23,892
  • 18
  • 70
  • 90
  • Why not jut put that struct on stack? Say `Context context;` instead of `malloc`-ing? Wouldn't that save you that bookeeping? – Dmitry Feb 02 '10 at 20:27
  • @Dmitry: the problem is that you must guarantee that the lifetime of the variable extends beyond the usage in the thread. If you create a variable in the a function, launch the thread and exit the function, chances are that the local variable will be destroyed (and overwritten if another function is called) before the newly created thread gets to use it. Of course, if you know that is not the case (the same function that creates the thread also waits for completion, that could be a simple solution. – David Rodríguez - dribeas Feb 02 '10 at 20:40

4 Answers4

7

You can use Boost.Thread. It provides a type-safe way for you to pass more than one argument into your callable.

Yes, it has similar kinds of bookkeeping as your question stated, but it uses C++ mechanisms to ensure that it doesn't leak.

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • 1
    Any thread library would be a good recomendation, but boost::thread is the closest I know to the next standard threads, so this is probably the best recomendation for someone that programs C++ – David Rodríguez - dribeas Feb 02 '10 at 20:41
4

Is there a better way to do this?

Not really. Since thread functions can only take a single void * argument, any and all data that you want to pass to the thread function has to be part of a struct or class that contains the data you need. The usual design pattern is to have a ThreadParameters class or struct that contains everything that you need, and which you can add to if you need to have more parameters.

The most straightforward way to handle freeing is to have the person that creates the thread allocate the ThreadParameters, and have the thread itself free the ThreadParameters just before it exits.

JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
4

Unless you are passing the same C++ object as the this pointer to multiple concurrent threads, you should simply add the index to the object.

I would recommend having one object per thread, to make debugging easier if nothing else. Make your current this class a resource shared by reference between thread objects.

If that means adding new objects on the heap, simply delete them immediately after calling pthread_join. Not much room for error, really.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • The issue with putting the index in the object is that many objects are accessing the class, and I need a way to differentiate them. – Mike Feb 02 '10 at 20:31
  • @Mike: "many objects are accessing the class" doesn't make sense. Objects belong to classes and access other objects. It would probably improve the organization of your program to have an object to represent each thread, even if it only consists of an index and a pointer (and a `pthread_t` — where do you have your thread objects now?). The other good suggestion, to learn and use a thread library, is equivalent: any thread library will be centered on objects representing threads! – Potatoswatter Feb 02 '10 at 22:07
1

If there is an object (class instance) associated with each thread. (I inferred this from your reference to this.) You could just make the index a member of the class. This could be configured in the constructor or using alternatively using a setter.

class C { 
  Index index_; 
public:
  C(Index &index) : index_(idx) {}
  void Run() { ... }
}

Index workSet;
C worker(workSet);
worker.Run();
Marc Butler
  • 1,346
  • 7
  • 13