在一个简单的c++ 11四线程程序中,如果我注释标准输出打印行,我的两个消费者线程就不会返回
In a simple C++ 11 four-thread program, my two consumer threads are not returning if I comment stdout print lines
我正在用c++ 11学习同步原语。我必须为模板类编写这些方法,模板类是一个FIFO队列,其最大元素数量在构造时声明。
有两个线程将项目推入该队列,两个线程检索它们。它们是通过使用两个条件变量来同步的,以确保消费者线程只在队列不为空时弹出项目,而生产者线程只在队列未满时推送新项目。队列具有打开/关闭状态,该状态在两个条件变量的wait()调用中用作附加条件。当队列关闭时,线程应该不执行任何操作而返回。
// main.cpp
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[]){
BlockingQueue<int> bq(10);
int sum1=0, sum2=0;
std::thread c1([&bq,&sum1](){
int i;
while(bq.get(i)) sum1+=i;
});
std::thread c2([&bq,&sum2](){
int i;
while(bq.get(i)) sum2+=i;
});
std::thread p1([&bq](){
for(int i=0;i<1000;i+=2) bq.put(i);
});
std::thread p2([&bq](){
for(int i=0;i<1000;i+=2) bq.put(i+1);
});
p1.join();
std::cout<<"p1 thread returned."<<std::endl;
p2.join();
std::cout<<"p2 thread returned."<<std::endl;
bq.close();
c1.join();
std::cout<<"c1 thread returned."<<std::endl;
c2.join();
std::cout<<"c2 thread returned."<<std::endl;
std::cout<<"sum1: "<<sum1<<std::endl;
std::cout<<"sum2: "<<sum2<<std::endl;
std::cout<<"total: "<<sum1+sum2<<std::endl;
return 0;
}
下面是我创建的类:
// BlockingQueue.h
#include "stdafx.h"
template<class T> class BlockingQueue
{
std::mutex t_queue_mutex;
std::queue<T> t_queue;
int t_queue_cap_value;
bool isQueueOpen;
std::condition_variable put_condition;
std::condition_variable get_condition;
public:
BlockingQueue(int N);
~BlockingQueue(void);
bool put(T t_item);
bool get(T &t_item);
bool isOpen();
bool isFull();
bool isEmpty();
void close();
};
// BlockinQueue.cpp
#include "BlockingQueue.h"
#include "stdafx.h"
template <class T> BlockingQueue<T>::BlockingQueue(int N)
{
t_queue_cap_value=N;
isQueueOpen=true;
std::cout<<"Rejoice! A bq has been created!"<<std::endl;
}
template <class T> BlockingQueue<T>::~BlockingQueue(void)
{
}
template <class T> bool BlockingQueue<T>::isFull(){
if(t_queue_cap_value==t_queue.size())
return true;
else
return false;
}
template <class T> bool BlockingQueue<T>::isOpen(){
return isQueueOpen;
}
template <class T> void BlockingQueue<T>::close(){
isQueueOpen=false;
}
/* get method */
template <class T> bool BlockingQueue<T>::get(T &t_item){
bool exitThreadStatus=false;
if(!isOpen()){
put_condition.notify_all();
return false;
}
std::unique_lock<std::mutex> ul(t_queue_mutex);
get_condition.wait(ul, [this](){
//std::cout<<"Getter thread with get_id()="<<std::this_thread::get_id()<<" is waiting. isOpen()="<<isOpen()<<" and t_queue.empty()="<<t_queue.empty()<<std::endl;
if(!isOpen())
return true;
else
return !t_queue.empty();
});
if(isOpen()){
exitThreadStatus=true;
t_item=t_queue.front();
t_queue.pop();
}
std::cout<<"Extracted "<<t_item<<". After pop size()="<<t_queue.size()<<std::endl;
put_condition.notify_all();
return exitThreadStatus;
}
/* put method */
template <class T> bool BlockingQueue<T>::put(T t_item){
bool exitThreadStatus=false;
if(!isOpen()){
get_condition.notify_all();
return false;
}
std::unique_lock<std::mutex> ul(t_queue_mutex);
put_condition.wait(ul, [this](){
if(!isOpen())
return true;
else
return !isFull();
});
if(isOpen()){
exitThreadStatus=true;
t_queue.push(t_item);
}
std::cout<<"Inserting "<<t_item<<". After push size()="<<t_queue.size()<<std::endl;
get_condition.notify_all();
return exitThreadStatus;
}
template class BlockingQueue<int>;
每当我在get()和put()中保留两个std::cout行不加注释时,它似乎都能正常工作,得到以下输出(如预期):
Inserting 998. After push size()=2
Extracted 997. After pop size()=1
p1 thread returned.
Inserting 999. After push size()=2
Extracted 998. After pop size()=1
p2 thread returned.
Extracted 999. After pop size()=0
Extracted 998. After pop size()=0
c1 thread returned.
c2 thread returned.
sum1: 250000
sum2: 249500
total: 499500
如果我对cout行进行注释,两个收集线程似乎永远不会返回,我无法理解我的代码出了什么问题。有人知道吗?谢谢你!
带注释的输出:
Rejoice! A bq has been created!
p1 thread returned.
p2 thread returned.
尝试在close()中添加get_condition.notify_all()和put_condition.notify_all()。
据我所知,当close()被调用时,如果线程在get()中的get_condition.wait()中,它将永远停留在等待中。为什么这与cout语句一起工作,我不知道,尽管文档确实提到了"虚假唤醒"。
相关文章:
- 线程之间的布尔停止信号
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 如何从线程中的不同模块调用函数?
- 我可以计算多线程数的平均值吗?
- 为什么我的 std::atomic<int> 变量不是线程安全的?
- 我怎么知道C++编译器是否制作线程安全的静态对象代码
- 睡眠:(睡眠或usleep)并没有将我的线程中的所有内容悬挂在Linux中,而是在Windows中悬挂吗?为什么
- 我可以在没有静音的线程中读取线程中的bool变量
- 当我从C#代码调用C++代码时,它是线程安全的吗
- 我需要保护一个由一个线程编写并由多个线程读取的变量吗
- 在 C++ 中易变:我是否应该定义一个可能被几个线程更改的变量作为易失性
- 对我来说,使 boost::statechart::state_machine 线程安全的最简单方法是什么?
- c ++ 为什么我的日期解析不是线程安全的
- 我知道 pantheios 是线程安全的,但它是进程间安全的吗?
- 多线程:我需要用只读方法保护我的变量吗
- 我可以挂起除一个线程外的进程吗?
- 我可以制作一个线程安全的 std::atomic<vector<int>>吗?
- 我如何使任何c++库都是线程安全的
- 我需要并行化或多线程我的应用程序
- 如果我只需要变量在其他线程中的值,我应该在一个线程中锁定变量吗?如果我不需要它为什么它有效?