futex等待/唤醒对是否实现获取/释放语义?

时间:2019-05-17 19:02:24

标签: c++ linux multithreading thread-safety futex

给出此伪代码,其中全局存在一个原子int a,其初始化为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) ...
}

忽略虚假唤醒的可能性; 我们能否从上面的代码中推断出代码XY进行了同步?基本上,它可以归结为futex本身是否旨在实现跨语言的获取/释放语义。等待被唤醒。


有点背景:TSAN无法理解futex系统调用(例如,参见herehere)。

现在,通常,当使用futex来实现互斥量,信号量或其他一些同步原语时,一个 也具有一个原子变量,该原子变量通过“锁定”端加载了获取顺序,并在“解锁”侧按发布顺序存储。 (以上,我故意使用宽松的语义。)

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

这个问题主要与论坛帖子linked above中提供的建议有关,以使用获取/释放语义标记futex操作自身这样的标记正确吗?

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

1 个答案:

答案 0 :(得分:1)

来自man futex(2)

  

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

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

  

以该存储顺序执行的装入操作执行获取操作,存储执行释放操作,而读-修改-写操作同时执行获取操作和释放操作,加上一个总的顺序,其中所有线程以相同的顺序观察所有修改

换句话说,futex syscall在内核中的作用等同于C ++ 11:

a.compare_exchange_strong(..., std::memory_order_seq_cst, std::memory_order_seq_cst);