私は「同期化されたキュー」と呼ぶものを使用する傾向があります。通常のキューをラップし、必要に応じてロックと読み取りブロックの両方に Semaphore クラスを使用します。
#ifndef SYNCQUEUE_20061005_H_
#define SYNCQUEUE_20061005_H_
#include <queue>
#include "Semaphore.h"
// similar, but slightly simpler interface to std::queue
// this queue implementation will serialize pushes and pops
// and block on a pop while empty (as apposed to throwing an exception)
// it also locks as neccessary on insertion and removal to avoid race
// conditions
template <class T, class C = std::deque<T> > class SyncQueue {
protected:
std::queue<T, C> m_Queue;
Semaphore m_Semaphore;
Mutex m_Mutex;
public:
typedef typename std::queue<T, C>::value_type value_type;
typedef typename std::queue<T, C>::size_type size_type;
explicit SyncQueue(const C& a = C()) : m_Queue(a), m_Semaphore(0) {}
bool empty() const { return m_Queue.empty(); }
size_type size() const { return m_Queue.size(); }
void push(const value_type& x);
value_type pop();
};
template <class T, class C>
void SyncQueue<T, C>::push(const SyncQueue<T, C>::value_type &x) {
// atomically push item
m_Mutex.lock();
m_Queue.push(x);
m_Mutex.unlock();
// let blocking semaphore know another item has arrived
m_Semaphore.v();
}
template <class T, class C>
typename SyncQueue<T, C>::value_type SyncQueue<T, C>::pop() {
// block until we have at least one item
m_Semaphore.p();
// atomically read and pop front item
m_Mutex.lock();
value_type ret = m_Queue.front();
m_Queue.pop();
m_Mutex.unlock();
return ret;
}
#endif
スレッド実装で適切なプリミティブを使用して、セマフォとミューテックスを実装できます。
注: この実装は、キュー内の単一要素の例ですが、N が提供されるまで結果をバッファリングする関数で簡単にラップできます。文字のキューの場合は次のようになります。
std::vector<char> func(int size) {
std::vector<char> result;
while(result.size() != size) {
result.push_back(my_sync_queue.pop());
}
return result;
}