简体   繁体   中英

Thread Pool C++

I have the following for loop:

for (int i = 0; i < 100; i++) {
    someJob();
}

I want to run this function only with 5 threads, how can I do it?

What I'm tried is to make array with 5 threads and if the index is equal to 5 to wait all threads and to it again, but I'm sure there is another way to do that:

std::thread t[THREAD_COUNT];
int j=0;

 for (int i = 0; i < 100; i++) {
    t[j++] = std::thread(someJob);
    if (j == THREAD_COUNT)
    {
        for (int k = 0; k < THREAD_COUNT; k++)
        {
            if (t[k].joinable())
                t[k].join();
        }
        j = 0;
    }
}

Any suggestion? (I can't use boost)

Thanks!

You can simply use std::async for that.

If you want to execute this function 100 times in 5 different asynchronous actions , then each asynchronous function will execute the function 20 times:

std::vector<std::future> results;
results.reserve(5);
for (auto i = 0; i< 5 ;i++){
   results.emplace_back([]{
     for(auto j = 0; j < 20 ; j++){
       doSomeFunction();
     } 
   });
}

for (auto& f : results){
    f.get();
}

the same code can be modified to use naked std::thread .

You could make a function that tests your thread array to find a vacant thread to run each successive job on. Something like this:

// synchronized output to prevent interleaving of results
#define sync_out(m) do{std::ostringstream o; o << m << '\n'; std::cout << o.str();}while(0)

void someJob(int id)
{
    sync_out("thread: " << id);
}

template<typename Job>
void start_thread(std::vector<std::thread>& threads, Job&& job)
{
    // find an ended thread
    for(auto&& thread: threads)
    {
        if(thread.joinable()) // still running or waiting to join
            continue;

        thread = std::thread(job);
        return;
    }

    // if not wait for one
    for(auto&& thread: threads)
    {
        if(!thread.joinable()) // dead thread (not run or already joined)
            continue;

        thread.join();
        thread = std::thread(job);
        return;
    }
}

int main()
{

    std::vector<std::thread> threads(5); // 5 threads

    for(int i = 0; i < 100; i++)
        start_thread(threads, [=]{someJob(i);});

    // wait for any unfinished threads    
    for(auto&& thread: threads)
        if(thread.joinable())
            thread.join();
}

You should use a Thread Pool .

Specifically, you might use the C++ Thread Pool Library CPTL , with which your code would look like this:

ctpl::thread_pool p(2 /* two threads in the pool */);

for (int i = 0; i < 100; i++) {
    p.push(someJob, "additional_param");
}

Here's one way to implement a thread pool on the fly, while staying safe.

#include <thread>
#include <vector>
#include <algorithm>
#include <mutex>

void someJob() { /* some lengthy process */ }

int main()
{
    const size_t THREAD_COUNT = 5;
    std::vector<std::thread> threadPool;
    std::mutex mtx;               // to block access to the pool

    for (int i = 0; i < 100; i++) 
    {
        {
            // add new thread to the pool.
            std::lock_guard<std::mutex> lock(mtx);
            threadPool.emplace_back(std::thread([&mtx, &threadPool]()
            {
                someJob();

                // task is done, remove thread from pool
                std::lock_guard<std::mutex> lock(mtx);
                threadPool.erase(
                    std::find_if(threadPool.begin(), threadPool.end(), 
                    [](std::thread& x) 
                    { 
                        if (x.get_id() == std::this_thread::get_id())
                        {
                            x.detach();  // have to call detach, since we can't 
                            return true; // destroy an attached thread.
                        }
                        return false; 
                    })
                );
            }));
        }

        for (;;)
        {
            // wait for a slot to be freed.
            std::this_thread::yield();
            std::lock_guard<std::mutex> lock(mtx);
            if (threadPool.size() < THREAD_COUNT)
            {
                break;
            }
        }
    }

    // wait for the last tasks to be done
    for (;;)
    {
        std::this_thread::yield();
        std::lock_guard<std::mutex> lock(mtx); // works fine without.. but...
        if (threadPool.empty())                // <-- can't call join here, since detached 
        {                                      // threads are not joinable()
            break;
        }
    }
    return 0;
}

OpenMP will allow you to do this trivially, while hiding the entire threadpool. Most compilers have build in support, but consult your manual for the specific options. (gcc simply requires passing -fopenmp as an option).

#pragma omp parallel for num_threads(5)
for (int i = 0; i < 100; i++) {
    someJob(i);
}

will then split your work over 5 threads. If you leave out num_threads(5) it will choose a number of threads itselve.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM