2017-03-15 7 views
2

私はマルチスレッドについて学習しています。私はそれを呼び出すことができればセマフォを使用してプロデューサ/コンシューマの問題をシミュレートしたかったのです。Segfaultが待ち行列を同期しようとしています

キューを保持するクラスがあり、プロデューサはキューにintsをプッシュし、コンシューマはキューを取得して印刷します。私がシミュレートさ

class TestClass{ 
public: 
    void producer(int i){ 
     unique_lock<mutex> l(m); 
     q.push(i); 
     if(q.size()) 
      cnd.notify_all(); 
    } 

    void consumer(){ 
     unique_lock<mutex> l(m); 
     while(q.empty()){ 
      cnd.wait(l); 
     } 
     int tmp = q.front(); 
     q.pop(); 
     cout << "Producer got " << tmp << endl; 
    } 
    void ConsumerInit(int threads){ 
     for(int i = 0; i < threads; i++){ 
      thrs[i] = thread(&TestClass::consumer, this); 
     } 
     for(auto &a : thrs) 
      a.join(); 
    } 


private: 
    queue<int> q; 
    vector<thread> thrs; 
    mutex m; 
    condition_variable cnd; 
}; 

を以下のようであると私は呼び出すために少しコンソールアプリケーションを使用したデータ:

int main(){ 
    int x; 
    TestClass t; 
    int counter = 0; 
    while(cin >> x){ 
     if(x == 0) 
      break; 
     if(x == 1) 
      t.producer(counter++); 
     if(x == 2) 
      t.ConsumerInit(5); 
    } 
} 

したがって、ユーザーのプレス2つのスレッドがある場合は、ユーザー入力1、データは、キューの中に押し込まれたとき生まれた

たとえば、1 1と2、または2 1 1 を押すと、segfaultがスローされます。私のコードの理解がなぜ次のようになっているのか分かりません。2 1 1

私は5つのスレッドを初期化します。キューは空で、スリープ状態になります。番号をキューにプッシュすると、スリープ中のすべてのスレッドに通知されます。 ロックミューテックスをもう一度起動してキューから番号を取得し、その後ミューテックスをリリースすると、ミューテックスが解放されたとき別のスレッドが同じことを行い、ミューテックスをロック解除します.3番目のスレッドはロックされていません。そのキューは再び空であり、残りのスレッドと同じように再びスリープ状態になります。

この論理は正しいですか?もしそうなら、なぜこれがsegfaultを投げつけているのですか?そうでなければ、私はすべての説明を感謝します。

ありがとうございました!

//編集 答え:suggets、私は[]をvector.push_backに置き換えましたが、消費者は今データに何もせず、受け取ったり印刷したりしません。

+0

typo、ありがとう!それを更新しました – Darlyn

+0

ああ、ありがとうagain :) – Darlyn

答えて

1

あなたは

thrs[i] = thread(&CTest::consumer, this); 

を行うときは、クラッシュがだろうどこだ

thrs.emplace_back(&CTest::consumer, this); 

を行う必要がありますTHRSベクトルを拡大していません。

+0

それに気づき、push_backを追加しましたが、消費者は今データを何もしません。 – Darlyn

+0

ConsumerInitは、5つの入力が待機していない(したがって、プログラムがそれ以上の入力を行うことができない)場合、無期限にブロックします。あなたは "2 1 1"を入力していますか? –

+0

ユーザーinpuは2 1 1なので、スレッドを作成してから、キュー内の番号を2回押します。 – Darlyn

1

問題はマルチスレッドとは関係ありません。

for (int i = 0; i < threads; i++) { 
     thrs[i] = thread(&CTest::consumer, this); 

    //... 
    vector<thread> thrs; 

thrsベクトル空であり、そしてそれはエントリを持っているかのように、あなたがアクセスしようとしている:あなたはstd::vector外の境界がアクセスしています。エラーを表示するように

、使用:

 thrs.at(i) = thread(&CTest::consumer, this); 

、あなたが代わりにセグメンテーション違反のstd::out_of_range除いて迎えられるでしょう。

+0

はそれに気づき、push_backを追加しましたが、消費者はデータで何もしません。それを受け取り、印刷しません。 – Darlyn

+0

それが別の問題です。 – PaulMcKenzie

1

入力シーケンスが1 1 1 1 1 ... 2の形式でない場合、プログラムがデッドロックします。つまり、に先行する数字が1sの場合は5未満です。ここで

が理由です:

キューサイズの総要素が5未満であり、メインスレッドが5つの作成した消費者スレッドのいくつかは、要素を受信するためのキューを待ってブロックします、consumerInitを呼び出す場合。一方、メインスレッドはjoinの操作をブロックします。メインスレッドは、コンシューマスレッドがデータの消費を待っている間にコンシューマスレッドが終了するのを待つため、処理が進まなくなります。したがって、デッドロック。

1

問題はここにある:あなたは消費者が終了するのを待っている2を入力した後

for(auto &a : thrs) 
     a.join(); 

メインスレッドがここにブロックされます。だから、この時点の後に入力を入力していると思うが、cinは起こっていない。

これら2行を削除してから1と入力すると、プロデューサ/コンシューマがそのジョブを実行します。

関連する問題