トピックはそれを言います。他のデータ構造のようにイテレータが関与していないのに、なぜstd :: queue(または一般に任意のキュー)が本質的にスレッドセーフではないのか理解できません。
その一般的なルールによると
次のコード例では競合が発生しているはずです。
#include "stdafx.h"
#include <queue>
#include <thread>
#include <iostream>
struct response
{
static int & getCount()
{
static int theCount = 0;
return theCount;
}
int id;
};
std::queue<response> queue;
// generate 100 response objects and Push them into the queue
void produce()
{
for (int i = 0; i < 100; i++)
{
response r;
r.id = response::getCount()++;
queue.Push(r);
std::cout << "produced: " << r.id << std::endl;
}
}
// get the 100 first responses from the queue
void consume()
{
int consumedCounter = 0;
for (;;)
{
if (!queue.empty())
{
std::cout << "consumed: " << queue.front().id << std::endl;
queue.pop();
consumedCounter++;
}
if (consumedCounter == 100)
break;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::thread t1(produce);
std::thread t2(consume);
t1.join();
t2.join();
return 0;
}
すべてが正常に機能しているようです:-整合性違反なし/データ破損-消費者が要素を取得する要素の順序は正しい(0 <1 <2 <3 <4 ...)、もちろん本番。と短所。シグナリングが含まれていないため、印刷はランダムです。
!queue.empty()
を確認し、次のブロックを入力し、queue.first()
にアクセスする前に、別のスレッドが唯一の要素を削除(ポップ)することを想像して、空のキューをクエリします。
次のような同期キューを使用する
_#pragma once
#include <queue>
#include <mutex>
#include <condition_variable>
template <typename T>
class SharedQueue
{
public:
SharedQueue();
~SharedQueue();
T& front();
void pop_front();
void Push_back(const T& item);
void Push_back(T&& item);
int size();
bool empty();
private:
std::deque<T> queue_;
std::mutex mutex_;
std::condition_variable cond_;
};
template <typename T>
SharedQueue<T>::SharedQueue(){}
template <typename T>
SharedQueue<T>::~SharedQueue(){}
template <typename T>
T& SharedQueue<T>::front()
{
std::unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
return queue_.front();
}
template <typename T>
void SharedQueue<T>::pop_front()
{
std::unique_lock<std::mutex> mlock(mutex_);
while (queue_.empty())
{
cond_.wait(mlock);
}
queue_.pop_front();
}
template <typename T>
void SharedQueue<T>::Push_back(const T& item)
{
std::unique_lock<std::mutex> mlock(mutex_);
queue_.Push_back(item);
mlock.unlock(); // unlock before notificiation to minimize mutex con
cond_.notify_one(); // notify one waiting thread
}
template <typename T>
void SharedQueue<T>::Push_back(T&& item)
{
std::unique_lock<std::mutex> mlock(mutex_);
queue_.Push_back(std::move(item));
mlock.unlock(); // unlock before notificiation to minimize mutex con
cond_.notify_one(); // notify one waiting thread
}
template <typename T>
int SharedQueue<T>::size()
{
std::unique_lock<std::mutex> mlock(mutex_);
int size = queue_.size();
mlock.unlock();
return size;
}
_
front()
の呼び出しは、要素が追加されるまで待機し、基になるキューをロックして、一度に1つのスレッドのみがアクセスできるようにします。