How can I make sure there are a given number of threads at all times? (Also, is this a good usage of threads?)

StackOverflow https://stackoverflow.com/questions/19144570

Question

I've just started diving into multithreading using the standard library today. Below is what I've come up with so far. Though it works in principle, it does not start a new thread once one has finished, but rather starts 4 threads once the last 4 finished, so if the tasks take an unequal amount of time, it isn't very efficient. Also, if they don't finish in the correct order, they have to wait for the succeeding work to finish until their results are evaluated.

How could I achieve always having 4 threads (until the work runs out)? I would think you would need to employ some sort of watcher function, but I don't see how it is possible exactly without signals/slots. I'd also be happy if you could point me to the correct manuals online.

Also, since I have no experience using multiprocessing before today, please tell me where I might have employed bad practice.

Thank you in advance!

mueslo


Here is the threaded task:

void burn_task(MyClass* obj)
{
    //computationally intensive
    obj->burn();
}

And here is how it is called:

void getsStuffDone()
{
    //initialise everything
    int samples = 1000;    
    int num_threads = 4;

    std::vector<MyClass*> myclasslist;
    std::vector<std::thread*> threadlist;

    myclasslist.resize(num_threads);
    threadlist.resize(num_threads);

    int i = 0;

    //do the work
    while(i+1<samples)
    {
        //current_num_threads = min(num_threads, num_tasks_left)
        int current_num_threads = (samples-i-1>num_threads)? num_threads : samples-i-1;

        //create threads
        for(int t=0; t<current_num_threads; ++t)
        {
            myclasslist[t] = new MyClass(other_parameters,i+1); //i+1 so seed is never zero
            threadlist[t] = new std::thread(burn_task, myclasslist[t]);
            ++i;
        }

        //wait to finish, evaluate and clean up (delete)
        for(int t=0; t<current_num_threads; ++t)
        {
            threadlist[t]->join();

            useResultsContainedWithin(myclasslist[t])

            delete myclasslist[t];
            delete threadlist[t];
        }

        threadlist.clear();

    }
}
Was it helpful?

Solution

A common approach for handling a set number of threads performing some task is to start X threads, and then let each thread pick it's "work" from a common queue. In a really simple case, you'd simply, instead of doing i+1 and i++ in the loop that creates the thread, let i be a std::atomic<int>, and do:

void some_thread_function()
{
  for(;;)
  {
     int work_on = i.fetch_add(1);     // "work_on = i++;"
     if (work_on >= samples)
        break;
     ... // do actual work
  }
}

In a more complex case, you'd have a waitable queue that contains a more complex datatype to describe the "work" to be done.

This means you always have the "right" number of threads, and there is no overhead of creating/tearing down threads (if the threads run for quite some time (tenths of a second or longer), this is not an issue anyway, but for "short" runtimes it is quite possibly a factor.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top