C++ std :: mutex如何绑定到资源?

nik*_*iko 15 c++ concurrency mutex locking

编译器是否只是检查锁定和解锁语句之间正在修改哪些变量并将它们绑定到互斥锁,以便对它们进行独占访问?

或者mutex.lock()锁定当前范围内可见的所有资源?

Ric*_*ges 16

鉴于这m是一个类型的变量std::mutex:

想象一下这个序列:

int a;
m.lock();
b += 1;
a = b;
m.unlock();
do_something_with(a);
Run Code Online (Sandbox Code Playgroud)

这里有一个"明显的"事情:

从b的分配和b的增量被"保护"免受来自其他线程的干扰,因为其他线程将尝试锁定它m并且将被阻塞直到我们调用m.unlock().

而且还有一个更微妙的事情.

在单线程代码中,编译器将寻求重新加载加载和存储.如果没有锁定,编译器可以自由地重新编写代码,如果这在您的芯片组上更有效:

int a = b + 1;
//    m.lock();
b = a;
//    m.unlock();
do_something_with(a);
Run Code Online (Sandbox Code Playgroud)

甚至:

do_something_with(++b);
Run Code Online (Sandbox Code Playgroud)

然而std::mutex::lock(),unlock(),std::thread(),std::async(),std::future::get()等都是围栏.编译器"知道"它可能不会重新排序加载和存储(读取和写入),使得操作最终在您编写代码时指定的栅栏的另一侧.

1:
2:    m.lock(); <--- This is a fence
3:    b += 1;   <--- So this load/store operation may not move above line 2
4:    m.unlock(); <-- Nor may it be moved below this line
Run Code Online (Sandbox Code Playgroud)

想象一下如果情况不是这样会发生什么:

(重新排序的代码)

thread1: int a = b + 1;
  <--- Here another thread precedes us and executes the same block of code
  thread2: int a = b + 1;
  thread2: m.lock();
  thread2: b = a;
  thread2: m.unlock();
thread1: m.lock();
thread1: b = a;
thread1: m.unlock();
thread1:do_something_with(a);
thread2:do_something_with(a);
Run Code Online (Sandbox Code Playgroud)

如果你遵循它,你会发现b现在有错误的值,因为编译器正在努力让你的代码更快.

......而这只是编译器的优化.std::mutex等等还防止存储器高速缓存以更"最佳"的方式重新排序加载和存储,这在单线程环境中是好的,但在多核(即任何现代PC或电话)系统中是灾难性的.

这种安全性需要付出代价,因为在线程B读取相同数据之前必须刷新线程A的高速缓存,并且与高速缓存的内存访问相比,将高速缓存刷新到内存的速度非常慢.但是,请小姐.这是使并发执行安全的唯一方法.

这就是为什么我们希望在可能的情况下,在SMP系统中,每个线程都有自己的数据副本.我们不仅希望最大限度地减少锁定所花费的时间,还要最小化我们越过栅栏的次数.

我可以继续讨论std::memory_order修改器,但这是一个黑暗而危险的漏洞,专家经常会出错并且初学者没有希望做到这一点.

  • 你的最后一句话是轻描淡写的.:) (4认同)

Pet*_*ker 6

"互斥"是"互斥"的缩写; 使用互斥锁的正确规则是在输入修改线程之间共享的变量的任何代码之前锁定它,并在完成代码部分时将其解锁.如果一个线程锁定互斥锁,则任何其他尝试锁定互斥锁的线程都将被阻塞,直到拥有该互斥锁的线程将其解锁.这意味着一次只有一个线程在代码中可以修改共享变量,这消除了竞争条件.

互斥体的其余部分在某种程度上依赖于编译器魔法:它还阻止编译器将受保护代码内部的数据加载和存储移动到其外部,反之亦然,这是受保护代码保持受保护所必需的. .


mol*_*ilo 5

根本没有这样的聪明,让它正确工作是程序员的责任。

互斥锁就像没有墙壁的房子上的一扇可上锁的门。

您所能做的就是在门锁上时防止其他人通过门进入房子。
只有当每个人都同意专门从门进入房子时,门才有用,并且当门锁上时,等待里面的人解锁门并退出。
没有什么可以阻止坏人通过不存在的墙壁进入房子,除非你同意不可以。