3

给定这个伪代码,其中全局有一个原子 inta初始化为 0:

线程 1:

// ... some code here (X) ...
a.store(1, relaxed);
futex_wake(&a);

线程 2:

if (futex_wait(&a, 1) == woken_up) {
  assert(a.load(relaxed) == 1);
  // ... some code here (Y) ...
}

忽略虚假唤醒的可能性;我们可以从上面的代码中推断出代码X同步Y吗?基本上,它归结为 futex 本身是否意味着在唤醒的等待中实现获取/释放语义。


一点上下文:TSAN 不理解 futex 系统调用(例如,请参见此处此处)。

现在,通常,当使用 futex 来实现互斥锁、信号量或其他同步原语时,还有一个原子变量,它通过“锁定”端加载获取排序,并通过“解锁”存储在释放排序中边。(上面,我故意使用宽松的语义。)

该获取/释放足以实现同步,形式上是正确的,并且它被 TSAN 识别(它不会报告任何以这种方式实现的锁,例如 Qt 中的 QBasicMutex)。

这个问题主要是关于上面链接的论坛帖子中提供的建议,用获取/释放语义标记 futex 操作本身。这样的标记是否正确?

(我知道 C++ 抽象机对 . 一无所知futex。它甚至对 pthreads 一无所知,但 TSAN 知道,并且知道例如发生在 apthread_create之前的代码也发生在新创建的线程中运行的代码之前。在其他话说,这不是语言律师的问题……)

4

1 回答 1

2

来自man futex(2)

futex 字的值的加载、该值与预期值的比较以及实际的阻塞将自动发生,并且将相对于其他线程在同一个 futex 字上执行的并发操作完全排序。因此,futex 字用于连接用户空间的同步和内核的阻塞实现。类似于可能更改共享内存的原子比较和交换操作,通过 futex 阻塞是原子比较和阻塞操作。

该总排序对应于 C++ std::memory_order_seq_cst

具有此内存顺序的加载操作执行获取操作,存储执行释放操作,读取-修改-写入执行获取操作和释放操作,另外存在一个总顺序,其中所有线程都观察内存中的所有修改同样的顺序

换句话说,futex系统调用在内核中相当于 C++11:

a.compare_exchange_strong(..., std::memory_order_seq_cst, std::memory_order_seq_cst);
于 2019-05-17T19:21:56.290 回答