2017-01-05 22 views
0

要素を持っているときにイベントを生成するか、コールバックを呼び出して要素が利用可能であることを通知するFIFOオブジェクトが必要です。私が見る限り、std:queueはこれをサポートしていません。データをポップするイベントとしてFIFOとして使用できるオブジェクトはありますか?

私の場合、1つのスレッドがデータを生成し、他のスレッドがそれらを消費する必要がある2つのスレッドがあります。

最初のスレッドがデータを生成する速度は固定されていないため、データを格納するバッファを用意して、他のスレッドが比較的一定の方法でそれらを読み込んで処理できるようにする必要があります。

私は書き込み側を実装する方法を知っていますが、読者側では、キューをポーリングすると、キューの状態を確認する処理能力が失われています。これを行うにはより良い方法があるのでしょうか?

編集1

それはキューのスレッド安全性についてではなく、STD ::キューは、ポーリングに基づいて取り組んでいるが、私はイベントベースである何かを必要としています。 std :: queueはイベントベースではなく、新しいデータが利用可能になったときにコールバックを行いません。

+0

適切なSTLコンテナまたはパターンをお探しですか? –

+0

@RawN明らかに、STLに既にコンテナがある場合は、それを実装する方法が良いでしょう。 – mans

+0

キューがあり、デキューがあります。既存のクラステンプレートから継承することを検討している場合 - そうしないでください。 –

答えて

0

あなたが質問を正しく理解していれば、C++ std::condition_variablesを使用して、キュー内のアイテムの利用可能性についてスレッド間で通知し、コールバックを呼び出すことができます。

コードは次のようになります。ここでは、メインスレッドは、発電機のスレッドとして動作し、消費者のスレッド私はあなたが持っているしたい場合がありますwhileループ内の任意の終了条件を追加していない

std::condition_variable Cv_; 
std::mutex Mutex_; 
std::queue<int> qVal; 

void callback() { 
    cout << "Callback Called with queue Value =>" << qVal.front() << endl; 
    qVal.pop(); 
} 
void ReceiveThread() { 

    while (true) { 
     std::unique_lock<mutex> Lock(Mutex_); 
     Cv_.wait(Lock); 
     callback(); 
    } 
} 

int main() { 
    thread thrd(ReceiveThread); 
    int pushVal = 1; 
    while (1) { 
     this_thread::sleep_for(std::chrono::seconds(1)); 
     qVal.push(pushVal); 
     cout << "Signalling for callback with value = " << pushVal<< endl; 
     pushVal++; 
     Cv_.notify_all(); 
    } 
} 

としてスレッド行為を受信します。

これが役に立ちます。

+0

ありがとう、std :: queueはスレッドセーフではないので、このコードは正常に動作します。std :: queueがいつでも1つのスレッドによってのみ使用されるというガードはありません。私が間違っている? – mans

+0

@マン:あなたは間違っていません。 "Mutex_"でキューに入れる前にメインスレッドをガードする必要があります。私のコードは主にあなたがしようとしていることを達成する方法を示すことを意図していたので、私はそれをしませんでした。 –

+0

ありがとう、非常に感謝しています。 std:queueへのアクセスを保護するために同じmutex(Mutex_)を使用できますか?新しいmutexが必要ですか? – mans

0

std::queue::push()機能が正常にqueue内の要素を挿入した後にcall_back functionが起動になるだろうように、我々はそれに私たちのcall_back function参照をシンプルに置くことができるようなその中の任意のプレースホルダを持っていません。

std::queue::push(data) 
{ 
    //add data to internal container 

    //placeholder section-------- 
    //invoke call_back function or event. 
    //placeholder section-------- 
} 

ので、このようなプレースホルダが存在しない場合には、我々は自動call_back functionの呼び出しやRAIIを使用して、いくつかのイベントを試すことができます。

実際のデータをstructの中にラップすると、通知に役立つとします。次に、structのオブジェクトを介して間接的に実際のデータにアクセスする必要があります。今

struct data_notifier 
{ 
    //the true data. 
    int actual_data; 

    data_notifier(int data) : actual_data(data) 
    { 
     //signal event queue_full  
     //or 
     //call a call_back function. 
    } 
} 

int actual_data = 90; 
std::queue<data_notifier*> q; 
q.push(new data_notifier(actual_data)); 

、唯一の問題は、次のとおりです。data_notifierのインスタンスが適切に参照/ポインタとしてqueueに挿入される前に、私たちのcall_backまたはイベントが呼び出さなるだろう。イベントが呼び出されると、リーダーはデータを読み込もうとしますが、データがまだキュー内に保持されていないため、キューからデータを取得しません。 したがって、キュー内で適切に保持されているデータの保証は、std::queue::push()関数が返された後にのみ可能です。Writer関数内で発生する可能性があります。

//event_full is a manual event which needs to be signalled and non-signalled manually. 

void Writer() 
{ 
    while(1) 
    { 
     //[1] wait for mutex_queue 
     //[2] myqueue.push(data); 
     //[3] data is now persisted so signal event_full 
     //[4] release mutex_queue 
    } 
} 

void Reader() 
{ 
    while(1) 
    { 
     //[1] wait for event_full (so no polling) 

     //[2] wait for mutex_queue 

     //[3] --- access queue --- 
     if(myqueue.size() != 0) 
     { 
      //process myqueue.front() 
      //myqueue.pop(); 
     } 
     if(myqueue.size() == 0) 
     { 
      //reset event_full  
      //so as long as queue has data, Reader can process it else needs to wait. 
     } 
     //[3] --- access queue --- 

     //[4] release mutex_queue 
    } 
} 
関連する問題