如何正确使用std::atomic_signal_fence()?

17

cppreference.com把这个函数描述为“线程和执行在同一线程中的信号处理程序之间的障碍(fence)”。但我在互联网上没有找到任何示例。

我想知道以下伪代码是否正确地说明了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
我认为信号处理程序是针对Unix系统类型信号的一种处理方式,具有特殊的线程规则。 - Tony The Lion
7
你的代码中没有任何信号处理程序,所以不,这段代码并没有展示出 atomic_signal_fence 的任何有意义的内容。 - Kerrek SB
3
有了适当的栅栏,就不需要使用volatile。这正是原子操作和栅栏的关键所在。 - Pete Becker
5
不需要volatile关键字,只要使用围栏或其他原子操作(使用适当的内存访问说明符),编译器就不允许这样做。在这种情况下,volatile是多余的。 - Pete Becker
3
signal_fence是一种“编译器屏障”,它可以防止编译器对内存操作进行重新排序/合并/提升,但永远不会发出硬件内存屏障指令。Jeff Preshing的博客非常好地解释了这个问题,如果您对内存排序方面还不确定,那么肯定要读一读。 - Peter Cordes
显示剩余2条评论
2个回答

23
不,你的代码并没有展示出正确使用atomic_signal_fence。正如你引用的cppreference.com所说,atomic_signal_fence仅在信号处理程序和同一线程上运行的其他代码之间执行同步。这意味着它不会在两个不同的线程之间执行同步。你的例子展示了两个不同的线程。

C++规范对该函数包含以下注意事项:

注意: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);
}

如果遇到断言,它保证为真。


你的例子中,A和B一定是原子性的吗? - Alex
@Alex 他们需要具有原子性。从技术上讲,如果没有原子性,几乎永远无法保证。 - curiousguy

6
在你的例子中,你想使用 std::atomic_thread_fence(生成机器代码以执行线程同步);而不是 std::atomic_signal_fence(仅禁用原子变量上的编译器内存重排序优化)。
正如其他人所说,std::atomic_signal_fence 仅适用于与原子操作在同一线程上的信号(我相信这也适用于 Windows 上的结构化/向量化异常处理程序,但请勿引用我)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接