8

スレッドセーフな方法でテストおよび設定する必要がある単純なブール値があります。1 つのスレッドが既に動作している場合は、2 番目のスレッドを終了させます。私がstd::atomic_flag正しく理解していれば、これはうまくいくはずです。ただし、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。皆さんありがとう!

4

2 に答える 2

8

atomic_flag広く使用されることを意図していない、非常に低レベルの構造です。そうは言っても、例外的な場合にフラグをクリアする可能性を除いて、意図したとおりに使用できると思います。一致したもの以外の例外std::exceptionが発生した場合、フラグはクリアされません。

通常、RAII はこの種のものに使用する必要があります。「R」は通常「リソース」を表しますが、代わりにジョン・カルブの「責任」の使い方が好きです。フラグを設定した後は、完了時にフラグをクリアする責任があるため、責任が確実に実行されるように 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
}
于 2013-04-04T20:05:43.023 に答える
1

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

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

編集:

いいえ、atomic_boolあなたが望むことは簡単にはできません。固執するatomic_flag...

于 2013-04-04T19:59:30.047 に答える