15

cppreference.com は、この機能を「スレッドと、同じスレッドで実行されるシグナル ハンドラーとの間のフェンス」として文書化しています。しかし、私はインターネット上で例を見つけませんでした。

次の疑似コードが の機能を正しく示しているかどうか疑問に思いますstd::atomic_signal_fence():

int n = 0;
SignalObject s;

void thread_1()
{
    s.wait();
    std::atomic_signal_fence(std::memory_order_acquire);
    assert(1 == n); // never fires ???
}

void thread_2()
{
    n = 1;
    s.signal();
}

int main()
{
    std::thread t1(thread_1);
    std::thread t2(thread_2);

    t1.join(); t2.join();
}
4

2 に答える 2

23

いいえ、あなたのコードは の正しい使い方を示していませんatomic_signal_fence。cppreference.com を引用atomic_signal_fenceすると、シグナル ハンドラーと同じスレッドで実行されている他のコードの間でのみ同期を実行します。つまり、2 つの異なるスレッド間の同期は実行されません。あなたのコード例は、2 つの異なるスレッドを示しています。

C++ 仕様には、この関数に関する次の注意事項が含まれています。

注:コンパイラの最適化とロードとストアの並べ替えは、 と同じ方法で禁止されますatomic_thread_fenceが、atomic_thread_fence が挿入したであろうハードウェア フェンス命令は発行されません。

注: atomic_signal_fenceを使用して、スレッドによって実行されたアクションがシグナル ハンドラーから見えるようになる順序を指定できます。

以下は、やる気を起こさせるものではないにしても、正しい使用例です。

static_assert(2 == ATOMIC_INT_LOCK_FREE, "this implementation does not guarantee that std::atomic<int> is always lock free.");

std::atomic<int> a = 0;
std::atomic<int> b = 0;

extern "C" void handler(int) {
    if (1 == a.load(std::memory_order_relaxed)) {
        std::atomic_signal_fence(std::memory_order_acquire);
        assert(1 == b.load(std::memory_order_relaxed));
    }

    std::exit(0);
}

int main() {
    std::signal(SIGTERM, &handler);

    b.store(1, std::memory_order_relaxed);
    std::atomic_signal_fence(std::memory_order_release);
    a.store(1, std::memory_order_relaxed);
}

アサーションは、遭遇した場合、真であることが保証されています。

于 2013-01-29T23:32:20.237 に答える
6

あなたの例では、std::atomic_thread_fence(スレッド同期を実行するマシンコードを生成する)を使用したいと考えています。そうではありませんstd::atomic_signal_fence(アトミック変数でのコンパイラ メモリの並べ替えの最適化のみを無効にします)。他の人が言ったstd::atomic_signal_fenceように、アトミック操作と同じスレッド上のシグナルのみを対象としています(Windowsの構造化/ベクトル化された例外ハンドラーにも当てはまると思いますが、引用しないでください)。

于 2013-03-18T04:13:31.290 に答える