2012-03-30 9 views
2

C++ Concurrency In Actionの本から少し変更したコードがあります。 。 私は何をしようとしたが、その内のスレッドまたはスレッドのために私がすることができ、その後、ストアバックグラウンドジョブスレッドセーフなキューを実装することです キューは次のようになります。condition_variableとunique_lockを使って周期的クラッシュを引き起こす(GCC 4.7、OSX)

queue.h

#pragma once 
#include "imgproc/i_queue.h" 
#include <memory> 
#include <thread> 
#include <queue> 
#include <mutex> 
#include <condition_variable> 

using namespace std; 

namespace imgproc { 

    /* Blocking, concurrency-safe queue. The method that blocks is pop(), 
    * which makes the current thread wait until there is a value to pop 
    * from the queue. 
    */ 
    template <typename T> 
    struct ConcurrentQueue : public IQueueWriter<T>, public IQueueReader<T> 
    { 
     ConcurrentQueue() {} 
     ConcurrentQueue(const ConcurrentQueue &) = delete; 
     ConcurrentQueue & operator= (const ConcurrentQueue &) = delete; 

     /* Concurrency-safe push to queue. 
     */ 
     virtual void push(shared_ptr<T> val) 
     { 
     lock_guard<mutex> lk(_mutex); 
     _queue.push(val); 
     _cvar.notify_one(); 
     } 

     /* Concurrency-safe check if queue empty. 
     */ 
     virtual const bool empty() const 
     { 
     lock_guard<mutex> lk(_mutex); 
     bool result(_queue.empty()); 
     return result; 
     } 

     /* Waiting, concurrency-safe pop of value. If there are no values in 
     * the queue, then this method blocks the current thread until there 
     * are. 
     */ 
     virtual shared_ptr<T> pop() 
     { 
     unique_lock<mutex> lk(_mutex); 
     _cvar.wait(lk, [ this ] {return ! _queue.empty(); }); 
     auto value(_queue.front()); 
     _queue.pop(); 
     return value; 
     } 

    private: 
     mutable mutex _mutex; 
     queue<shared_ptr<T>> _queue; 
     condition_variable _cvar; 
    }; 

} 

私の理解では、1つのミューテックスがキューにアクセスしようとするすべての試みを保護すべきです。しかし、私は10で、約1時間のクラッシュテストを持っている:

テスト - その-クラッシュ-fragment.cpp

// Should have threads wait until there is a value to pop 
TEST_F(ConcurrentQueueTest, 
     ShouldHaveThreadsWaitUntilThereIsAValueToPop) { 
    int val(-1); 
    thread t1([ this, &val ] { 
     for (uint i(0) ; i < 1000 ; ++i); 
     val = *_r_queue->pop(); 
    }); 
    for (uint i(0) ; i < 1000 ; ++ i) { 
    for (uint j(0) ; j < 1000 ; ++ j); 
    EXPECT_EQ(-1, val); 
    } 
    _w_queue->push(make_shared<int>(27)); 
    t1.join(); 
    EXPECT_EQ(27, val); 
    EXPECT_TRUE(_r_queue->empty()); 
} 

を変数_r_queue_w_queueちょうどここで、同じConcurrentQueueインスタンス上のインターフェイスです。

デバッグ情報を徹底的に取り除くのに費やした時間から、インスタンス変数が空の場合、常にpop()への呼び出しがクラッシュの原因になっているように見えます。 誰でも私が間違っていることについてアドバイスをしてくれますか?私は同様の問題について助けを求めている他の投稿を見たことがありますが、条件変数が答えであると言われています。

これを解決するために、これをよりよくデバッグする方法についてのアドバイスはありますか? FWIW、私は手作業でsleep(1)を持ってwhileを実装しようとしましたが、それでも定期的にクラッシュしてしまいました。これはむしろ私の努力にもかかわらず競争状態になることを示唆しています。

ありがとうございました&すべての助けを借りて、私はそれをすべて気にする前にこれを理解しようとしました。

乾杯、 ダグ。

+0

こんにちは - 詳細については、問題のコードを1つのメインファイルに取り出しました。このプログラムはコンパイルされると終了するはずですが、実際にはt.join()の最後の呼び出しでハングします。メインファイルはここにあります:https://gist.github.com/2396866 – biot023

答えて

1

https://gist.github.com/2396866を読み取ることで、私はこの問題は、テスト中であることを識別//どちらもした後も、無期限にキューをpop'ing保つ。同時にポップ値」。2つのスレッドが作成され、その後分離されることができるはずです。。テストはこれが(問題があるように思われる)最後のテストに影響を及ぼし終了

そのための迅速な解決策は次のようになります。彼らは50弦それぞれをポップする場合、スレッドが死ぬようになります

/* ... */ 

{ // Should be able to concurrently pop values 
    for (uint i(0) ; i < 100 ; ++ i) 
    q.push(make_shared<string>("Monty Halfwit")); 

    pair<uint, uint> counts(0, 0); 
    thread t1([ & ] { 
    while (++counts.first != 50) { 
     this_thread::sleep_for(chrono::milliseconds(1)); 
     q.pop(); 
    } 
    }); 

    thread t2([ & ] { 
    while (++counts.second != 50) { 
     this_thread::sleep_for(chrono::milliseconds(1)); 
     q.pop(); 
    } 
    }); 

    t1.detach(); 
    t2.detach(); 

/* ... */ 

関連する問題