views:

156

answers:

4

I'm working on a library doing audio encoding/decoding. The encoder shall be able to use multiple cores (i.e. multiple threads, using boost library), if available. What i have right now is a class that performs all encoding-relevant operations.

The next step i want to take is to make that class threaded. So i'm wondering how to do this.

I thought about writing a thread-class, creating n threads for n cores and then calling the encoder with the appropriate arguments. But maybe this is an overkill and there is no need for another class, so i'm going to make use of the "user interface" for thread-creation.

I hope there are any suggestions.

Edit: I'm forced to use multiple threads for the pre-processing, creating statistics of the input data using CUDA. So, if there are multiple Cards in a system the only way to use them in parallel is to create multiple threads.

Example: 4 Files, 4 different calculation units (separate memories, unique device id). Each of the files shall be executed on one calculation unit.

What i have right now is:

class Encoder {
[...]
public:
    worker(T data, int devId);
[...]
}

So i think the best way is to call worker from threaded from main()

boost::thread w1(&Encoder::worker, data0, 0);
boost::thread w2(&Encoder::worker, data1, 1);
boost::thread w3(&Encoder::worker, data2, 2);
boost::thread w4(&Encoder::worker, data3, 3);

and not to implement a thread-class.

+2  A: 

Have a look at OpenMP, if your compiler supports it. It can be as easy as adding a compiler flag and spraying on a few #pragmas.

Thomas
I'm using OpenMP in parallelizing loops. I made an edit to be more precise on the problem to be solved, forcing me to use multiple threads.
macs
OpenMP creates threads for you. I'm still not sure what your problem is, but I guess you know best.
Thomas
Oh, i see ... thanks. I'll give it a try.
macs
The problem is, that i were not shure WHERE to put that code. I wanted to put it inside my encoder-class to hide as much complexity as possible from the user. But i've realized now, that it doesn't matter if it is inside the class or inside the interface.
macs
+1  A: 

I think the problem is more at a design level, can you elaborate a bit on what classes do you have ? I work on CUDA too, and usually one creates an interface (aka Facade pattern) for using the architecture specific (CUDA) layer.

Edit: After reading the update interface I think you are doing the right thing. Keep the Encoder logic inside the class and use plain boost::threads to execute different units of work. Just pay attention on thread safety inside Encoder's methods.

fabrizioM
I've tried to give a slight overview of the encoder class (extremely simple)
macs
+1  A: 

Your current suggestion only works if Encoder::worker is static. I assume that is the case. One concern would be, if your current implementation supports a way to gracefully abort an encoding-job. I suppose there is some method in your code of the form:

while( MoreInputSamples ) {
    // Do more encoding
}

This may be modified with some additional condition that checks if the jobs has received an abort signal. I work on video-decoding a lot and i like to have my decoder classes like that:

class Decoder {
public:
    void DoOneStepOfDecoding( AccessUnit & Input );
}

The output usually goes to some ring-buffer. This way, I can easily wrap this in both single-and multithreaded scenarios.

Space_C0wb0y
+1  A: 

The preceding code

  boost::thread w1(&Encoder::worker, data0, 0);

is not valid until worker is static.

There is Boost.Task on th review Schedule that allows you to call asynchronously any callable, as follows

  boost::tasks::async(
    boost::tasks::make_task( &Encoder::worker, data0, 0) ) );

This results in Encoder::worker been called on a default threadpool. The function returns a handle that allows to know when the task has been executed.

Vicente Botet Escriba