0

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.

Sebastian
  • 8,046
  • 2
  • 34
  • 58
  • The output of the next frame in most encoders relies on the output of the previous n-frames. Might this be a problem? – spender Mar 15 '10 at 10:05
  • Please don't worry about the encoding problem to be solved ... _it is_. I'm not going to do parallel encoding if it won't work. Anyway ... i've made an edit ... the multiple threads are for pre-processing, where the output does _not_ rely on previous input. – Sebastian Mar 15 '10 at 10:09
  • @spender; There's a bunch of options for doing a/v coding in parallel, for example, most (video at least) streams rely on key frames to recover from dropped frames, so you could start encoding multiple parts of your stream starting at each key frame. Some streams use multiple encodings, e.g. one high def and one low def which could be encoded in parallel (probaly offset to allow the high def to use the low def as input), and so on. – falstro Mar 15 '10 at 10:11
  • I do not understand your problem. If you have on critical operations, multithreading is trivial. Could you post relevant parts of the interface you are trying to use multithreaded, or maybe post possible solutions you are considering? – Björn Pollex Mar 15 '10 at 10:27
  • @Space_C0wb0y: Tried to explain it more clearly above. – Sebastian Mar 15 '10 at 10:37

4 Answers4

2

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
  • 174,939
  • 50
  • 355
  • 478
  • 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. – Sebastian Mar 15 '10 at 10:09
  • OpenMP creates threads for you. I'm still not sure what your problem is, but I guess you know best. – Thomas Mar 15 '10 at 10:15
  • 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. – Sebastian Mar 16 '10 at 10:32
1

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
  • 46,639
  • 15
  • 102
  • 119
1

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.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
1

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
  • 4,305
  • 1
  • 25
  • 39