C ++中队列中的线程池

时间:2017-12-31 12:42:46

标签: c++ multithreading c++11

我一直在尝试同时解决问题,这非常适合线程池模式。在这里,我将尝试提供一个最小的代表性示例:

假设我们有这样的伪程序:

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

我正在尝试以并行方式实现它,使用n-1个工作线程和一个主线程。工作人员将通过抓取Q中的元素在内循环中执行计算。

我尝试使用两个条件变量work来解决这个问题,主线程在其上通知工作人员已经分配了Q,另一个work_done,其中工作人员通知主人,整个计算可能会完成。

这是我的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;
}

不幸的是,在使用g++ -std=c++11 -Wall -o main main.cpp在OS X上编译它之后,我得到以下输出:

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

经过一段时间的谷歌搜索,它看起来像一个分段错误。它可能与我滥用条件变量有关。我很欣赏一些见解,包括架构(关于如何处理这类问题)和具体问题,就像我在这里做错了一样。

我很感激帮助

2 个答案:

答案 0 :(得分:2)

您的申请被std::terminate杀死。

你的线程函数的主体是无限循环,所以当这些行被执行时

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

您要删除仍在运行的线程(每个线程都处于可连接状态)。当你调用处于可连接状态的线程的析构函数时,会发生以下事情(来自http://www.cplusplus.com/reference/thread/thread/~thread/

  

如果线程在销毁时是可连接的,则调用terminate()。

因此,如果您不希望调用terminate,则应在创建线程后调用detach()方法。

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

答案 1 :(得分:2)

仅仅因为队列是空的并不意味着工作已经完成。

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

我们需要一些方法来终止线程

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