2016-03-25 25 views
1

私のマルチスレッドアプリケーションでは、同じstd::dequeを使用する2つのスレッドがあります。それらのうちの1つはそれに書き込み、もう一方はそれから読み取る(データ分析のために)。同じデキューにアクセスするマルチスレッドのC++

私はこのエラーを取得する:

Deque iterator not dereferencable

EDIT: これは私が両端キューからの読み取りに使用するコードです。 if-conditionのどこかでエラーが発生します(ここでは、dequeにはatでアクセスしています)。

for (int i = 0; i <myDeque.size(); i++){ 
    try{ 
     if (myDeque.at(i) > 10){ 
      //do stufff 
     } 
    } 
    catch (...){ 
     cout << "ERROR" << endl; 
    } 
} 

これは、このようなことが、この両端キューのマルチスレッドアクセスによって発生すると仮定します。 try-catchブロックでエラーをキャッチできません。もっと深い「飛行機」に投げ込まれているので、私はこれを行うことはできませんか? このエラーを修正する可能性はありますか?

+0

は 'deque'空ですか? –

+0

いいえ、空ではありません。 – black

+1

デキューオブジェクトへのアクセスをシリアル化するために同期メカニズム(ロックやmutexなど)を使用していますか?もしそうでなければ、あなたはすべきです。これは、複数のスレッドが共有データ構造にアクセスできるようにする場合の標準ソリューションです。 –

答えて

2

ロックを使用しますか?いくつかの一般的にアクセス可能な場所では、mutexを宣言:

std::mutex deque_lock; 

そして包むことblocks that acquire itdequeに読み込みと書き込み:

... nondeque stuff ... 
{ 
    std::lock_guard<std::mutex> lock(deque_lock); 
    mydeque.push_back(...); 
} 
... more nondeque stuff... 

と読み:

... nondeque stuff ... 
{ 
    std::lock_guard<std::mutex> lock(deque_lock); 
    for (const auto& elem : mydeque) { 
     ... do stuff with each element, ideally cheap things to avoid blocking writer ... 
    } 
} 
... more nondeque stuff... 

保つようにしてくださいロックされたブロック内で最小限に働きます。高価な作業の場合は、ロックの下の値をコピーし、ロックなしでそれを使用して他のスレッドをブロックしないようにすることができます。

+0

ブロックされたメモリにアクセスするとき、他のスレッドは何をしますか?停止しているのですか、それとも単純に "deque"して、両端キューで実行したい操作をドロップしますか? – black

+0

@blackブロックされ、処理を続行するためにmutexのロックを取得できるまで待ちます。 –

+0

@ShadowRangerありがとう!だから私は書き込みプロセス(push_back)のためにこれを行うでしょう。私は読書のためにそれをやるべきでしょうか? (私の質問のforループのために)。私は25の要素を読んでいます(この例ではわずか10です)。これは長すぎるのですか? – black

3

ここでは、キューを介して通信するリーダ/ライタのペアの非常に単純な例を示します。

注やるべき仕事とライターが(それがキューを空にしていますとき、読者が停止することができますことを知らせる)が終了したかどうかがあるかどうかについての通信を同期させるcondition_variableの使用:

#include <iostream> 
#include <thread> 
#include <deque> 
#include <condition_variable> 

std::mutex m; 
std::condition_variable reader_action; 
bool all_written = false; 

std::deque<int> buffer; 

// note: this function is called with the mutex unlocked 
// we have popped i from the buffer 
void handle_read_event(int i) 
{ 
    if (i % 100000 == 0) 
     std::cout << i << std::endl; 
} 

int main() 
{ 
    std::thread writer([]{ 
     for (int i = 0 ; i < 1000000 ; ++i) 
     { 
      { 
       auto lock = std::unique_lock<std::mutex>(m); 
       buffer.push_back(i); 
       lock.unlock(); 
       reader_action.notify_one(); 
      } 
     } 

     auto lock = std::unique_lock<std::mutex>(m); 
     all_written = true; 
     lock.unlock(); 
     reader_action.notify_one(); 
    }); 

    std::thread reader([]{ 
     while(1) 
     { 
      auto lock = std::unique_lock<std::mutex>(m); 
      reader_action.wait(lock, [] { return all_written || (!buffer.empty()); }); 
      if (!buffer.empty()) { 
       int i = buffer.front(); 
       buffer.pop_front(); 
       lock.unlock(); 
       handle_read_event(i); 
      } 
      else if(all_written) 
      { 
       break; 
      } 
     } 
    }); 

    writer.join(); 
    reader.join(); 
    return 0; 
} 

予想される出力:

0 
100000 
200000 
300000 
400000 
500000 
600000 
700000 
800000 
900000 

我々は、我々は我々がキューを排出しながら、ライター待ちをする気にしないことを決定した場合、我々はこのように第二のスレッドを実装することができます:

...または私たちの目的に合った他の戦略。