ブロッキングキューは、テイクアンドプットをサポートするキューです。
take操作は、キューから要素を取得します。キューが空の場合、takeは、キューに使用可能な要素ができるまでブロックします。
put操作は要素をキューに入れます。キューがいっぱいになると、キューに空きスペースができるまでputはブロックされます。
単純なブロッキングキューを実装するには、最初に非常に低レベルのコンテナを用意する必要があります。ベクトル、deque、さらにはリストについては、ここではコンテナとしてdequeを選択します。
前に定義したブロッキングキューは制限されています。つまり、要素には上限があるため、完全な要素ブロッキングが発生します。
デフォルトで要素を常に保存できる、単純な無制限のブロッキングキューから始めましょう。したがって、キューが要素でいっぱいかどうかを判断する必要はありません。現時点では、キューが空でブロックされていることを判別するための条件変数のみが必要です。おおよそのフレームワークは次のとおりです。
template<typename T>
class BlockQueue{
std::deque<T> que;
std::condition_variable empty;
std::mutex mtx; // declared for unique_lock;
public:
T take();
void put(T elem);
int size();
}
では、コアテイクアンドプットをどのように実現するのでしょうか?
まず、キューを変更する操作をロックする必要があります。同時プログラミングで変数変数を変更する場合は、ロックする必要があります。残念ながら、putとtakeの両方でキューが変更されます。
ここではunique_lockを使用してロックします
std::unique_lock<std::mutex> lock{mtx};
2つの操作のうち、take操作のみがキューを空にするため、takeはキューが空であると判断する必要があり、ここでは条件変数が使用されます。
empty.wait(lock, [this]{return !que.empty();});
だから私たちのプットアンドテイク操作が出てきました
template<typename T>
T BlockQueue::take(){
std::unique_lock<std::mutex> lock{mtx};
empty.wait(lock, [this]{return !que.empty();});
auto res = que.front():
que.pop_front():
return res;
}
template<typename T>
void BlockQueue::put(T elem){
std::unique_lock<std::mutex> lock{mtx};
que.push_back(T elem);
}
著者:固定点P
リンク:https://www.jianshu.com/p/9dd1b7863667
出典:ジェーンの本
は著者が著作権を所有しています。商用の再版については、承認を得るために作者に連絡してください。非商用の再版については、出典を示してください。