简体   繁体   English

C ++中队列上的线程池

[英]Thread pool on a queue in C++

I've been trying to solve a problem concurrently, which fits the thread pool pattern very nicely. 我一直在尝试同时解决问题,这非常适合线程池模式。 Here I will try to provide a minimal representative example: 在这里,我将尝试提供一个最小的代表性示例:

Say we have a pseudo-program like this: 假设我们有一个伪程序,如下所示:

Q : collection<int>
while (!Q.empty()) {
    for each q in Q {
        // perform some computation
    }
    // assign a new value to Q
    Q = something_completely_new();
}

I'm trying to implement that in a parallel way, with n-1 workers and one main thread. 我正在尝试以n-1工作人员和一个主线程以并行方式实现这一点。 The workers will perform the computation in the inner loop by grabbing elements from Q . 工作人员将通过从Q获取元素在内部循环中执行计算。

I tried to solve this using two conditional variables, work , on which the master threads notifies the workers that Q has been assigned to, and another, work_done , where the workers notify master that the entire computation might be done. 我试图使用两个条件变量来解决这个问题,两个是work变量,主线程在该变量上通知工作人员已经分配了Q,另一个工作work_done ,在工作work_done中通知工作人员整个计算可能已完成。

Here's my C++ code: 这是我的C ++代码:

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <thread>

using namespace std;

std::queue<int> Q;
std::mutex mut;
std::condition_variable work;
std::condition_variable work_done;

void run_thread() {
    for (;;) {
        std::unique_lock<std::mutex> lock(mut);
        work.wait(lock, [&] { return Q.size() > 0; });

        // there is work to be done - pretend we're working on something
        int x = Q.front(); Q.pop();
        std::cout << "Working on " << x << std::endl;

        work_done.notify_one();
    }
}

int main() {
    // your code goes here
    std::vector<std::thread *> workers(3);

    for (size_t i = 0; i < 3; i++) {
        workers[i] = new std::thread{
            [&] { run_thread(); }
        };
    }

    for (int i = 4; i > 0; --i) {
        std::unique_lock<std::mutex> lock(mut);
        Q = std::queue<int>();
        for (int k = 0; k < i; k++) {
            Q.push(k);
        }
        work.notify_all();
        work_done.wait(lock, [&] { return Q.size() == 0; });
    }

    for (size_t i = 0; i < 3; i++) {
        delete workers[i];
    }

    return 0;
}

Unfortunately, after compiling it on OS X with g++ -std=c++11 -Wall -o main main.cpp I get the following output: 不幸的是,在OS X上使用g++ -std=c++11 -Wall -o main main.cpp编译后,得到以下输出:

Working on 0
Working on 1
Working on 2
Working on 3
Working on 0
Working on 1
Working on 2
Working on 0
Working on 1
Working on 0
libc++abi.dylib: terminating
Abort trap: 6

After a while of googling it looks like a segmentation fault. 经过一段时间的搜寻后,它看起来像是分割错误。 It probably has to do with me misusing conditional variables. 这可能与我滥用条件变量有关。 I would appreciate some insight, both architectural (on how to approach this type of problem) and specific, as in what I'm doing wrong here exactly. 我希望能从结构上(关于如何解决此类问题)和特定的见识中获得一些见识,就像我在这里做错的那样。

I appreciate the help 感谢您的帮助

Your application was killed by std::terminate . 您的应用程序被std::terminate杀死。

Body of your thread function is infinite-loop, so when these lines are executed 线程函数的主体是无限循环的,因此在执行这些行时

for (size_t i = 0; i < 3; i++) {
    delete workers[i];
}

you want to delete threads which are still running (each thread is in joinable state). 您想要删除仍在运行的线程(每个线程处于可连接状态)。 When you call destructor of thread which is in joinable state the following thing happens (from http://www.cplusplus.com/reference/thread/thread/~thread/ ) 当您调用处于可连接状态的线程的析构函数时,会发生以下情况(来自http://www.cplusplus.com/reference/thread/thread/~thread/

If the thread is joinable when destroyed, terminate() is called. 如果线程在销毁时是可连接的,则调用terminate()。

so if you want terminate not to be called, you should call detach() method after creating threads. 因此,如果您不希望terminate被调用,则应在创建线程后调用detach()方法。

  for (size_t i = 0; i < 3; i++) {
    workers[i] = new std::thread{
        [&] { run_thread(); }
    };
    workers[i]->detach();  // <---
}

Just because the queue is empty doesn't mean the work is done. 仅仅因为队列为空并不意味着工作已经完成。

finished = true;
work.notify_all();
for (size_t i = 0; i < 3; i++) {
    workers[i].join(); // wait for threads to finish
    delete workers[i];
}

and we need some way to terminate the threads 我们需要某种方式来终止线程

for (;!finshed;) {
    std::unique_lock<std::mutex> lock(mut);
    work.wait(lock, [&] { return Q.size() > 0 || finished; });
    if (finished)
      return;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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