我有这个非常简单的小型C ++程序,可以创建线程池,然后将消息放在线程之间共享的阻塞队列中对每个线程说什么。
消息可以是: -1 (流结束 - >终止), -2 (屏障 - >等待所有线程到达它,然后继续),其他值进行随机计算。循环按以下顺序完成:一些计算,屏障,一些计算,屏障,......,屏障,流结束,线程连接,退出。
即使池中有2个线程,我也无法理解为什么我会获得死锁。队列不能变空,但是我推送和弹出消息的顺序总是会导致空队列!
阻塞队列实现是这里提出的(C++ Equivalent to Java's BlockingQueue),只添加了两个方法。我还复制了下面的队列代码。
任何帮助?
Main.cpp的
#include <iostream>
#include <vector>
#include <thread>
#include "Queue.hpp"
using namespace std;
// function executed by each thread
void f(int i, Queue<int> &q){
while(1){
// take a message from blocking queue
int j= q.pop();
// if it is end of stream then exit
if (j==-1) break;
// if it is barrier, wait for other threads to reach it
if (j==-2){
// active wait! BAD, but anyway...
while(q.size() > 0){
;
}
}
else{
// random stuff
int x = 0;
for(int i=0;i<j;i++)
x += 4;
}
}
}
int main(){
Queue<int> queue; //blocking queue
vector<thread> tids; // thread pool
int nt = 2; // number of threads
int dim = 8; // number to control number of operations
// create thread pool, passing thread id and queue
for(int i=0;i<nt;i++)
tids.push_back(thread(f,i, std::ref(queue)));
for(int dist=1; dist<=dim; dist++){ // without this outer loop the program works fine
// push random number
for(int j=0;j<dist;j++){
queue.push(4);
}
// push barrier code
for(int i=0;i<nt;i++){
queue.push(-2);
}
// active wait! BAD, but anyway...
while (queue.size()>0){
;
}
}
// push end of stream
for(int i=0;i<nt;i++)
queue.push(-1);
// join thread pool
for(int i=0;i<nt;i++){
tids[i].join();
}
return 0;
}
Queue.hpp
#include <deque>
#include <mutex>
#include <condition_variable>
template <typename T>
class Queue
{
private:
std::mutex d_mutex;
std::condition_variable d_condition;
std::deque<T> d_queue;
public:
void push(T const& value) {
{
std::unique_lock<std::mutex> lock(this->d_mutex);
d_queue.push_front(value);
}
this->d_condition.notify_one();
}
T pop() {
std::unique_lock<std::mutex> lock(this->d_mutex);
this->d_condition.wait(lock, [=]{ return !this->d_queue.empty(); });
T rc(std::move(this->d_queue.back()));
this->d_queue.pop_back();
return rc;
}
bool empty(){
std::unique_lock<std::mutex> lock(this->d_mutex);
return this->d_queue.empty();
}
int size(){
std::unique_lock<std::mutex> lock(this->d_mutex);
return this->d_queue.size();
}
};
答案 0 :(得分:0)
我认为问题在于你的积极等待,你描述为&#34; BAD,但无论如何......&#34;并使用队列的大小作为障碍,而不是使用真正的synchronization barrier
对于dim = 1,你推送一个有4,-2,-2的队列。一个线程将抓住4和-2而另一个线程抓住剩余的-2。此时队列为空,您有三个线程(两个工作线程和主线程)正在进行主动等待,以查看队列是否已清空。大小互联网只允许一次读取大小。如果首先调度主线程并确定该队列为空,则它将按下-1,-1以指示流的结束。现在,队列不再是空的,但是两个工作线程中的一个或两个正在等待它清空。由于他们在获取另一个项目之前等待它为空,因此队列在此状态下处于死锁状态。
对于案件是dim&gt; 1在将两个工作确认清空队列并退出活动等待之前,将下一组值推入主线程的队列中可能存在类似的问题。
答案 1 :(得分:-1)
我运行了你的代码,我理解了这个问题。问题出在&#34; -2&#34;选项。当两个线程到达此时,您的主线程已经将另一个值推送到队列中。所以,如果你的队列在线程获得的时间和#34; -2&#34;之间增加了它的大小。价值,在他们到达&#34; -2&#34;之前选项,您的代码将卡住: 线程1:得-2。 线程2:得-2。 线程主:推-1。 线程主:推-1。 线程1:等待直到整个队列都为空。 线程2:等待直到整个队列都是空的。
队列: -1 -1
^如果dim等于1.在你的代码中,dim等于8,你不想看到它的样子。 为了解决这个问题,我所做的就是禁用以下循环:
username
当这个pard禁用时,代码运行完美。 这是我检查它的方式:
for(int i=0;i<nt;i++){
queue.push(-2);
}
结果:
std::mutex guarder;
// function executed by each thread
void f(int i, Queue<int> &q){
while(1){
// take a message from blocking queue
guarder.lock();
int j= q.pop();
guarder.unlock();
// if it is end of stream then exit
if (j==-1) break;
// if it is barrier, wait for other threads to reach it
if (j==-2){
// active wait! BAD, but anyway...
while(q.size() > 0){
;
}
}
else{
// random stuff
int x = 0;
for(int i=0;i<j;i++)
x += 4;
guarder.lock();
cout << x << std::endl;
guarder.unlock();
}
}
}
int main(){
Queue<int> queue; //blocking queue
vector<thread> tids; // thread pool
int nt = 2; // number of threads
int dim = 8; // number to control number of operations
// create thread pool, passing thread id and queue
for(int i=0;i<nt;i++)
tids.push_back(thread(f,i, std::ref(queue)));
for(int dist=1; dist<=dim; dist++){ // without this outer loop the program works fine
// push random number
for(int j=0;j<dist;j++){
queue.push(dist);
}
/*// push barrier code
for(int i=0;i<nt;i++){
queue.push(-2);
}*/
// active wait! BAD, but anyway...
while (queue.size()>0){
;
}
}
// push end of stream
for(int i=0;i<nt;i++)
queue.push(-1);
// join thread pool
for(int i=0;i<nt;i++){
tids[i].join();
}
return 0;
}
顺便说一下,卡住了没有发生,因为你的'等待'#34;部分。它不好,但通常会导致其他问题(比如减慢系统速度)。