2013-04-04 20 views
6

私はスレッドセーフな方法でテストして設定する必要がある単純なブール値を持っています。あるスレッドがすでに動作している場合は、2番目のスレッドを終了します。 std::atomic_flagが正しく理解されていれば、正常に動作するはずです。まともなを形成し、以下の提案に基づいて更新されたコード:C++ 11 std :: atomic_flag、これを正しく使用していますか?

// myclass.cpp 
#using <atomic> 

namespace // anonymous namespace 
{ 
    std::atomic_flag _my_flag = ATOMIC_FLAG_INIT; 
} // ns 

myclass::do_something() 
{ 
    if (!::_my_flag.test_and_set())) 
    { 
     // do my stuff here; handle errors and clear flag when done 
     try 
     { 
      // do my stuff here 
     } 
     catch (...) 
     { 
      // handle exception 
     } 

     ::_my_flag.clear(); // clear my flag, we're done doing stuff 
    } 
    // else, we're already doing something in another thread, let's exit 
} // do_something 

更新:しかし、私は私が正しくstd::atomic_flagを理解し:)私は、このスピンロック、たとえば、保存、オンライン多くの簡単な例を見つけることができないよう自信がないんだけどstd::atomic_flagの適切な使用のためのテンプレート。皆さんありがとう!

+0

このコードは機能しませんか? –

+0

@BrendanLong - まだ完全にテストしていません。私がベンチャーになる前に私がコンセプトを最初に得ていることを確かめたいと思っています。「私のものをする」という部分は私の場合かなり広範囲になるでしょう。私は簡単に必要に応じてmutexを使用するようにこのコードを修正することができると認識しています... – Tom

+0

あなたの質問に疑問符はありません。 – inf

答えて

5

atomic_flagは広く使われることを意図していない本当に低レベルの構成です。それは例外的な場合にはフラグをクリアすることを除いて、あなたが意図したとおりの使用法であると信じています。 std::exceptionと一致するもの以外の例外が発生した場合、フラグはクリアされません。

通常、この種の処理にはRAIIを使用します。 「R」は通常「リソース」を表しますが、代わりにJon Kalbのusageの「責任」が好きです。フラグを設定したら、完了時にフラグをクリアする責任があるので、RAIIを使用して責任が実行されるようにする必要があります。例外的な場合に行う必要があるすべての操作をこのように行うことができる場合は、try/catchのペアが消えます。

if (!std::atomic_flag_test_and_set(&::_my_flag)) 
{ 
    flag_clearer x(&::_my_flag); 

    // do my stuff here 
} 

しかし、あなた自身でflag_clearerタイプを書く必要はありません。代わりに、mutexやlock_guardなどの上位レベルの構造を単純に使用できます。

namespace 
{ 
    std::mutex my_flag; 
} 

myclass::do_something() 
{ 
    if (my_flag.try_lock()) 
    { 
     std::lock_guard<std::mutex> x(my_flag, std::adopt_lock); 
     // do my stuff here 
    } 
    // else, we're already doing something in another thread, let's exit 
} 
+1

ありがとうございました。 RAIIポイントはよく取られています。そして、あなたが正しいです、私は例外処理についてうんざりしました。単純な理由から、まだflag_clearerを使用しないようにしたいのであれば、 'catch(std :: exception&e)'を 'catch(...)'に置き換え、それを良いと呼ぶことができますか?私はおそらくあなたが提案したもので私のコードを置き換えようとしています。もしそれがあまり秘密にならないようにするには、私のアプリでこのセクションのパフォーマンスを最後まで落とす必要はありません。ありがとうございました – Tom

+1

@Tomはい、 '...'をキャッチすると、クリーンアップコードが実行されます。 – bames53

+0

フォローアップをありがとう、私は改訂されたコードで私のポストを更新します...そしてあなたのミューテックスの例で私の実際のコードを置き換え:)再びありがとう! – Tom

1

他のスレッドがすでにフラグを設定していて、誰もそれをクリアしていない場合は、ifブロック内のコードをスキップします。他のコードでフラグが壊れていない場合、そのスレッドが現在そのブロックを実行していることを意味します。

原子フラグはかなり低いレベルですが、代わりにatomic_boolの使用を検討してください。また、これはC++であるため、セットとクリアのメンバー関数を使用できます。

EDIT:

いや、atomic_boolは簡単にあなたがやりたいことはありません。 atomic_flagとスティック

+0

ピート、確認していただきありがとうございます。私はメンバ関数を代わりに使用しますが、それらは読みやすくなります。再度、感謝します! – Tom