2017-07-03 7 views
0

私は2つのスレッドによってアクセスされる共有ベクトルを持っています。共有ベクトルアトムブールとの同期

スレッドAの関数はベクトルにプッシュし、スレッドBの関数は処理のためにベクトルを完全にスワップします。

MovetoVec(PInfo* pInfo) 
    { 
     while(1) 
     { 
      if(GetSwitch()) 
      { 
       swapBucket->push_back(pInfo); 
       toggles = true; 
       break; 
      } 
      else if(pInfo->tryMove == 5) 
      { 
       delete pInfo; 
       break; 
      } 
      pInfo->tryMove++; 
      Sleep(25); 
     } 
    } 

スレッドAがtrueにアトミックブールtogglesを取得しようとベクター中に押し込む。(上記MoveToVec機能スレッドの多くの数によって呼び出されます)。 GetSwitchがここ

GetSwitch() 
{ 
    if(toggles) 
    { 
     toggles = false; 
     return TRUE; 
    } 
    else 
     return FALSE; 
} 

togglesのように定義された関数は、ベクトルがGetSwitchがfalseを返す場合threadBは何もしません

GetClassObj(vector<ProfiledInfo*>* toSwaps) 
    { 
     if(GetSwitch()) 
     { 
      toSwaps->swap(*swapBucket); 
      toggles = true; 
     } 
    } 

あるスワップスレッドBからatomic_bool.And別の関数です。ここで私はどんなロックを使用しています。それはほとんどの場合に機能します。しかし、swapBucketにあるpInfoオブジェクトのうちの1つはNULLです。私はそれが同期不良のためだということを知る必要があります。

私はこのタイプのGetSwitch()ロジックに従い、ロックによって引き起こされるオーバーヘッドを無視しています。私はこれをドロップアウトし、ミューテックスまたはクリティカルセクションのものに戻すべきですか?

答えて

4

GetSwitch実装が間違っています。複数のスレッドがスイッチを同時に取得することは可能です。

ちょうど2つのスレッドを持つそのようなシナリオの例:

Thread 1     | Thread 2 
--------------------------|-------------------------- 
if (toggles)    | 
          | if (toggles) 
    toggles = false;  | 
          |  toggles = false; 

ザテスト場合割り当てがアトミック操作ではなく、したがって、自分でスレッドを同期させるために使用することができません。


アトミックブール値を同期の手段として使用する場合は、1つのアトミック操作で値を比較して交換する必要があります。幸いなことに、C++は、弱い強い風味で利用可能なstd::compare_exchangeという操作を提供します(弱いものは偽って失敗するかもしれませんが、ループで呼び出されると安いかもしれません)。この操作を使用して

は、あなたのGetSwitch方法はなる:

bool GetSwitch() 
{ 
    bool expected = true; // The value we expect 'toggles' to have 
    bool desired = false; // The value we want 'toggles' to get 

    // Check if 'toggles' is as expected, and if it is, update it to the desired value 
    bool result = toggles.compare_exchange_strong(&expected, desired); 

    // The result of the compare_exchange is true if the value was updated and false if it was not 
    return result; 
} 

これは、値を比較し、更新がアトミックに起こることを保証します。

C++標準では、アトミックブール値がロックフリーであることを保証していないことに注意してください。あなたの場合は、標準でロックフリーであることが保証されているstd::atomic_flagを使用することもできます。例を注意深く読んでください。原子変数とは少し違います。


あなたがしようとしているように、ロックフリーコードを書くことは非常に複雑でエラーを起こしやすいです。

私の助言は、まずロックでコードを書いて100%正しいことを確認することです。実際にはミューテックスは驚くほど速いので、ほとんどの場合、パフォーマンスは大丈夫です。ロックのパフォーマンスをよく読んでください:http://preshing.com/20111118/locks-arent-slow-lock-contention-is

コードをプロファイリングしてロックがパフォーマンスに影響していると確信した場合にのみ、コードをロックフリーで書くようにしてください。ロックフリーのコードが必ずしも速いわけではないので、再度プロファイルします。

関連する問題