【问题标题】:Code before/after lock always execute serially?锁之前/之后的代码总是串行执行?
【发布时间】:2021-10-05 11:37:53
【问题描述】:
CodeBlockA;

Lock;
CodeBlockB;
Unlock;

CodeBlockC

代码块可能包含很多代码,以它为一个单元即可。

CodeBlockA CodeBlockB CodeBlockC 是否总是串行执行? lock 是如何实现的?

【问题讨论】:

  • 我相信是的。看看this。
  • 这取决于您所说的“串行”是什么意思。在单个线程中,在某些意义上它实际上可能不是串行的,但除非您导致 UB,否则代码的可观察行为将就像它一样。如果其他线程可以看到代码块的效果,它们可能会或可能不会按顺序观察这些效果,除非锁包含适当的内存屏障。查找“C 内存排序”。
  • 锁定/解锁仅在您运行多个线程或进程时才有意义。相对于那些它可以并行或以任何顺序运行。但是,在单个线程或进程中,执行顺序不能改变。因此,除非您的“锁定/解锁”有其他含义,否则您的代码会在编写时执行。

标签: c mutex critical-section spinlock lockless


【解决方案1】:

现在,我不知道其他系统,但在 linux 上是这样的:

pthreads

在 NPTL 中,线程同步原语(互斥锁、线程连接等)是使用 Linux futex(2) 系统调用实现的。

futex

当执行请求阻塞线程的 futex 操作时, 仅当 futex 字具有以下值时,内核才会阻塞 提供的调用线程(作为 futex() 调用)作为 futex 字的期望值。这 加载 futex 字的值,该值的比较 与期望值,实际阻塞将发生 原子地并且将相对于并发完全排序 其他线程对同一个 futex 字执行的操作。 因此,futex 字用于连接同步 用户空间由内核执行阻塞。 类似于原子比较和交换操作 可能会更改共享内存,通过 futex 阻塞是 原子比较和阻塞操作。

C - mtx_lock

在同一个互斥体上对 mtx_unlock 的先前调用与此操作同步,并且任何给定互斥体上的所有锁定/解锁操作形成一个单一的总顺序(类似于原子的修改顺序)

C Standard n2596

7.26.4 互斥函数

为了确定是否存在数据竞争,锁定和解锁操作的行为类似于 原子操作。对特定互斥体的所有锁定和解锁操作都发生在某个特定的 总订单。

注意这个总顺序可以看作是互斥体的修改顺序。

【讨论】:

  • 附近代码块的内存访问也有总序?
  • 我会说不。因此,您必须同步(或构建障碍)。但正如 futex 文档所解释的那样,互斥变量的“修改”(加载、比较和实际阻塞)保证是有序的。超越锁定/解锁不。
猜你喜欢
  • 1970-01-01
  • 2013-05-31
  • 1970-01-01
  • 1970-01-01
  • 2016-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多