2017-12-20 5 views
-1

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'; 
    } 
} 

今、睡眠が危険な場合、プロデューサーやコンシューマーに欲しいと思ったら、少し絞り込んでみましょう。

+0

(1)は必要ありません。そうでなければ 'プロデューサー'が眠っている間ロックを保持し、それによって '消費者'が飢えてしまうからです。また、あなたのプログラムは未定義の振る舞いをしています: 'g_queue'にローカル変数へのポインタを設定します。このポインタは、ポインタが取り出されて逆参照されるまでに非常に破壊されるかもしれません。 –

+0

はい、私は今それを理解しています。飢えは、私が(1)と(2)の両方を取り除いて走っていたときに見ることができる行動の原因です。だから、私はsleep文を削除し、出力に文脈の切り替えを見ることができました。また、私はローカル変数の問題を理解することができ、私のコードでもそれを修正しました。 – cpp11dev

答えて

0

ここでもまだ質問はありませんが、スロットルの解決策の1つは、キューがプロデューサで成長できる最大サイズを持つことです。キューがこのサイズに達すると、プロデューサは異なる条件変数で待機します。キューが特定のサイズを下回ると、コンシューマはこの第2の条件変数を通知します。 (いくつかのヒステリシスを与えるために後者のサイズはおそらく最大値より多少小さい)この新しい条件変数の待機の述語はg_queue.size() >= max_sizeです。

+0

はい、これはまだ問題でした。スロットルの管理のために、上記のコードを書き直すことができます。ここでは、キューバッファの空白とフルネスを管理するために2つの新しいCVが必要です。もう一度やり直してみましょう。ありがとうございました。 – cpp11dev

関連する問題