我使用這個類的生產者 - 消費者安裝在C++:C++線程安全的隊列關機
#pragma once
#include <queue>
#include <mutex>
#include <condition_variable>
#include <memory>
#include <atomic>
template <typename T> class SafeQueue
{
public:
SafeQueue() :
_shutdown(false)
{
}
void Enqueue(T item)
{
std::unique_lock<std::mutex> lock(_queue_mutex);
bool was_empty = _queue.empty();
_queue.push(std::move(item));
lock.unlock();
if (was_empty)
_condition_variable.notify_one();
}
bool Dequeue(T& item)
{
std::unique_lock<std::mutex> lock(_queue_mutex);
while (!_shutdown && _queue.empty())
_condition_variable.wait(lock);
if(!_shutdown)
{
item = std::move(_queue.front());
_queue.pop();
return true;
}
return false;
}
bool IsEmpty()
{
std::lock_guard<std::mutex> lock(_queue_mutex);
return _queue.empty();
}
void Shutdown()
{
_shutdown = true;
_condition_variable.notify_all();
}
private:
std::mutex _queue_mutex;
std::condition_variable _condition_variable;
std::queue<T> _queue;
std::atomic<bool> _shutdown;
};
我用它是這樣的:
class Producer
{
public:
Producer() :
_running(true),
_t(std::bind(&Producer::ProduceThread, this))
{ }
~Producer()
{
_running = false;
_incoming_packets.Shutdown();
_t.join();
}
SafeQueue<Packet> _incoming_packets;
private:
void ProduceThread()
{
while(_running)
{
Packet p = GetNewPacket();
_incoming_packets.Enqueue(p);
}
}
std::atomic<bool> _running;
std::thread _t;
}
class Consumer
{
Consumer(Producer* producer) :
_producer(producer),
_t(std::bind(&Consumer::WorkerThread, this))
{ }
~Consumer()
{
_t.join();
}
private:
void WorkerThread()
{
Packet p;
while(producer->_incoming_packets.Dequeue(p))
ProcessPacket(p);
}
std::thread _t;
Producer* _producer;
}
這工作最的時間。但在同時,一旦當我刪除生產者(並引起它的析構函數調用SafeQueue::Shutdown
,在_t.join()
塊永遠
我的猜測是,這個問題是這裏(SafeQueue::Dequeue
):
while (!_shutdown && _queue.empty())
_condition_variable.wait(lock);
SafeQueue::Shutdown
從線#1被調用,而線#2檢查完_Shutdown但在此之前它執行_condition_variable.wait(lock)
,因此「缺失」的notify_all()
。能這樣呢?
如果這是問題,解決問題的最佳方法是什麼?
覆蓋您是否打開了最高級別的警告?您的消費者類中有一個微妙的錯誤。您的數據成員的順序以及您打算在構造函數衝突中初始化它們的順序....檢查它。該線程將在分配_producer之前創建。 – WhiZTiM
同樣,您錯誤地使用了條件變量......它不應該像這樣處於while循環中。它有一個允許這樣的測試的過載 – WhiZTiM
@WhiZTiM我知道它有這樣的過載,但它相當於一個while循環:http://en.cppreference.com/w/cpp/thread/condition_variable/wait。 – UnTraDe