C++の11個のノートに基づいて非常に単純なプロデューサー/コンシューマーを作成しましたが、なぜunique_lock()が範囲外になったときにロックを解除しないのかわかりません。単純なプロデューサーとコンシューマーのunique_lockでの難しさ
struct Message{
Message(int x):data(x){cout<<"+";}
int data;
};
queue<Message*> g_queue;
condition_variable cv;
mutex m;
void consumer()
{
do {
unique_lock<mutex> lck {m};
cv.wait(lck, [&](){return !g_queue.empty();});
cout<<"Notified...";
auto& obj = g_queue.front();
std::cout<<obj->data;
g_queue.pop();
cout<<".";
lck.unlock(); -----(1)
} while(1);
}
void producer()
{
while(true){
unique_lock<mutex> lck {m};
Message msg{5};
cout<<"Queue size:"<<g_queue.size()<<'\n';
g_queue.push(&msg);
cv.notify_one();
lck.unlock(); -------(2)
cout<<"-"<<'\n';
this_thread::sleep_for(std::chrono::milliseconds{2000});
}
}
としてそれを使用する: - 出力がある
thread Q(&consumer);
thread P(&producer);
P.join();
Q.join();
: -
+Queue size:0
-Notified...
5.+Queue size:0
-Notified...5
.+Queue size:0
-Notified...5
だから、技術的には、はい、プロデューサーは、私は準備ができている消費者に伝える必要があると消費者にする必要がありますProducerにより多くのデータを送信させる。私は何を使うべきかについて明確ではない、条件変数がこれを行うのか、それともunique_lockがこれをするのか。
まさに、私が必要とする理由(1)及び(2)範囲は、以下のロック
==編集== を解放することができるときで正常に動作し、編集コード、
void consumer()
{
do {
unique_lock<mutex> lck {m};
cv.wait(lck, [&](){return !g_queue.empty();});
cout<<"Notified...";
auto& obj = g_queue.front();
std::cout<<obj->data;
g_queue.pop();
cout<<".";
} while(1);
}
Message msg{5};
void producer()
{
while(true){
unique_lock<mutex> lck {m};
cout<<"Queue size:"<<g_queue.size()<<'\n';
g_queue.push(&msg);
cv.notify_one();
cout<<"-"<<'\n';
}
}
今、睡眠が危険な場合、プロデューサーやコンシューマーに欲しいと思ったら、少し絞り込んでみましょう。
(1)は必要ありません。そうでなければ 'プロデューサー'が眠っている間ロックを保持し、それによって '消費者'が飢えてしまうからです。また、あなたのプログラムは未定義の振る舞いをしています: 'g_queue'にローカル変数へのポインタを設定します。このポインタは、ポインタが取り出されて逆参照されるまでに非常に破壊されるかもしれません。 –
はい、私は今それを理解しています。飢えは、私が(1)と(2)の両方を取り除いて走っていたときに見ることができる行動の原因です。だから、私はsleep文を削除し、出力に文脈の切り替えを見ることができました。また、私はローカル変数の問題を理解することができ、私のコードでもそれを修正しました。 – cpp11dev