Click to See Complete Forum and Search --> : dynamic assignment of work to threads


akotha1
July 10th, 2009, 02:02 PM
Hi ,

I am looking at writing multi-threaded programs exploring fine grained parallelism.

I want to create threads in the begining of a process and then assign work to them as i keep discovering parallelism.

I wanted to know if there was a way in pthreads or any other threading library where one could assign work to a thread after it is created.

i.e. we initialise it with one function. But after we definitely know that it is done, can we assign another function to it without recreating it.


Is there something very basic that I am missing?

JVene
July 10th, 2009, 06:36 PM
I've replied in several threads (:lol: posts) on this subject.

There are several threading libraries, but few if any perform what I consider to be among the most important service, which is almost exactly as you've described.

There is no basic service that does this. TBB from Intel does provide some interesting resources regarding parallel algorithms, and does some behind the scenes management of the appropriate thread resources, but it's not exactly what you've stated.

What TBB is doing is to create a C++ library that handles threaded loops and algorithms in a STL like fashion. Under the hood, and here I must presume, it may indeed create threads for use during execution of it's features (it would make little sense for it not to, IMO). Launching a thread takes time, and so it makes sense that a parallel performance oriented solution would examine the local hardware, spawn an appropriate number of threads in which to schedule the parallel work, and keep them waiting until work is made available. I have not seriously examined TBB to be certain this is what happens.

OpenMP is a means of giving the language itself some features to 'automatically' invoke parallel execution in some situations, but my own reaction is that TBB would be more controllable. OpenMP also hides the exact nature of it's support for launching/hold/scheduling threads, and while I assume it would be a reasonably intelligent design, I also recognize TBB has the potential to offer wider application (it should work even if the compiler doesn't support OpenMP).

Generally, though, threading is advantageous for purposes beyond complex parallel algorithmic support. Scheduling tasks for execution in response to GUI stimulus is a classic example. There are times when one simply would benefit from handing a serial process or two, which are otherwise entirely independent, into separate cores while the 'driving' thread continues with it's work.

For these situations one would want a process queue. I envision this as an object which launches a thread at it's creation, held waiting on an event, which accepts from application code function objects which represent any combination of functors, templates representing pointer to function, pointer to member function (with object or reference) - any number of calling scenarios. I've used them for years with great advantage. For example:



class SomeClass
{
private:

QueProcessor q;

public:

void somefunc();

void somecaller();

}

void SomeClass::somecaller()
{
q.Submit( this, &SomeClass::somefunc );
}



Variations on this construction abound.

q represent a thread which is launched and waits simply because it is in scope. The call in somecaller is all that's required for somefunc to execute on the thread represented by q.

It can accept a number of variations, including bind and function objects from STL and boost.

Variations on QueProcessor support thread pools and parallel execution of scheduled job components, something like a more primitive example of TBB.

If as many as hundreds or thousands of calls to submit are performed before 'somefunc' finished, the function objects are held in a deque container, performed in order as the que becomes available. Thread pool versions of the QueProcessor can launch additional threads based on rules which support service requirements (like opening new lanes of cash registers in a store to service long lines).

My own library isn't public, and I'm not aware of any that provide this service, but it's not all that difficult to create. It's utility, however, has proved beyond prediction. I wouldn't want to write GUI applications without them. Note - smart pointers (shared_ptr) becomes an important ally in this kind of work, both within such a library and in the application code which uses it.