在下面的代码中,我将创建一个producer thread
和n
consumer threads
,分别从其专用的queue
中读取并打印到stdout
。该代码有时会在语句consumerQueues[id]->empty()
上崩溃。通过调试器,我发现consumerQueues[id]
在崩溃时是0x0
。现在,在init()
函数中,我在创建ith
工作者queue
之前创建了ith
使用者thread
。我不确定为什么consumerQueues[id]
将保留为0x0
。请帮我弄清楚发生了什么。
#include <thread>
#include <queue>
#include <memory>
#include <iostream>
#include <mutex>
#include <condition_variable>
class Test
{
private:
void producer()
{
while(true)
{
std::string s = "abc";
for(const auto& q : consumerQueues)
{
std::unique_lock<std::mutex> lock(mutex);
q->push(s);
condition_variable.notify_all();
}
}
}
void consumer(int id)
{
while (true)
{
std::string job;
{
std::unique_lock<std::mutex> lock(mutex);
while(consumerQueues[id]->empty())
{
condition_variable.wait(lock);
}
job = consumerQueues[id]->front();
consumerQueues[id]->pop();
}
std::cout << "ID "<< id << " job " << job << std::endl;
}
}
std::mutex mutex;
std::condition_variable condition_variable;
std::vector<std::thread> workers;
std::vector<std::shared_ptr<std::queue<std::string>>> consumerQueues;
std::thread producerThread;
public:
Test(const unsigned n_threads):
workers(std::vector<std::thread>(n_threads))
{}
Test(const Test &) = delete;
Test(Test &&) = delete;
Test & operator=(const Test &) = delete;
Test & operator=(Test &&) = delete;
void init()
{
for (unsigned i = 0; i < workers.size(); ++i)
{
consumerQueues.push_back(std::make_shared<std::queue<std::string>>());
workers[i] = std::thread(&Test::consumer, this, i);
}
producerThread = std::thread(&Test::producer, this);
}
~Test()
{
producerThread.join();
for (unsigned i = 0; i < workers.size(); ++i)
{
if(workers[i].joinable())
{
workers[i].join();
}
}
}
};
int main()
{
Test t(1000);
t.init();
return 0;
}
答案 0 :(得分:5)
您的init函数正在修改没有互斥量的std :: vector。这将在线程逐个启动的同时修改向量。
要使其正常工作,您的init函数必须是这样的:
void init() {
for (unsigned i = 0; i < workers.size(); ++i) {
std::unique_lock<std::mutex> lock(mutex);
consumerQueues.push_back(std::make_shared<std::queue<std::string>>());
workers[i] = std::thread(&Test::consumer, this, i);
}
producerThread = std::thread(&Test::producer, this);
}
发件人:http://www.cplusplus.com/reference/vector/vector/push_back/
数据竞赛
容器已修改。如果发生重新分配,则所有包含 元素被修改。否则,将不访问任何现有元素,并且 同时访问或修改它们是安全的。
重新分配通常从0个元素开始到1000个时发生。因此,您还可以保留向量的大小,以确保没有发生重新分配:
void init() {
consumerQueues.reserve(workers.size());
for (unsigned i = 0; i < workers.size(); ++i) {
consumerQueues.push_back(std::make_shared<std::queue<std::string>>());
workers[i] = std::thread(&Test::consumer, this, i);
}
producerThread = std::thread(&Test::producer, this);
}