【问题标题】:How to correctly use std::atomic_signal_fence()?如何正确使用 std::atomic_signal_fence()?
【发布时间】:2013-01-12 21:59:27
【问题描述】:

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();
}

【问题讨论】:

  • 我认为信号处理程序是来自 unix 系统类型的信号,它具有特殊的线程规则。
  • 您的代码中没有任何信号处理程序,所以不,该代码没有展示任何关于atomic_signal_fence 的意义。
  • @StefanDragnev - 有了适当的围栏,就不需要volatile。这就是原子和栅栏的全部意义所在。
  • @StefanDragnev - 不,不允许编译器使用栅栏或任何其他原子操作(使用适当的内存访问说明符)这样做。在这种情况下,volatile 是多余的。
  • A signal_fence"compiler" barrier:它防止内存操作的编译时重新排序/组合/提升,但永远不会发出硬件内存屏障指令。 Jeff Preshing 的博客非常擅长解释这些内容,如果您不确定内存排序的内容,绝对是必读之物。

标签: c++ multithreading performance c++11 atomic


【解决方案1】:

不,您的代码没有证明atomic_signal_fence 的正确用法。当您引用 cppreference.com 时,atomic_signal_fence 仅在信号处理程序和在同一线程上运行的其他代码之间执行同步。这意味着它在两个不同的线程之间执行同步。您的示例代码显示了两个不同的线程。

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);
}

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

【讨论】:

  • 在您的示例中 A 和 B 是否一定是原子的?
  • @Alex 他们需要具有原子性。从技术上讲,它几乎永远不能保证没有原子。
【解决方案2】:

在您的示例中,您想使用std::atomic_thread_fence(它生成机器代码来执行线程同步);不是std::atomic_signal_fence(它只会禁用编译器对原子变量的内存重新排序优化)。 正如其他人所说,std::atomic_signal_fence 仅用于与原子操作在同一线程上的信号(我相信它也适用于 Windows 上的结构化/矢量异常处理程序,但不要引用我的话)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-10
    • 2013-01-28
    • 1970-01-01
    • 2020-04-24
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    • 2016-08-03
    相关资源
    最近更新 更多