Cur*_*ous 10 c++ multithreading synchronization mutex
我想知道最好问一下这样的问题,所以我在Meta(https://meta.stackexchange.com/questions/304981)上提出了这个问题并在这里进行了指导,所以这里有.
我非常好奇Google使用absl::Mutex(https://github.com/abseil/abseil-cpp/blob/master/absl/synchronization/mutex.h)对条件关键部分的实现进行了哪种优化.特别是我想知道当读者的情况变为现实时他们如何处理读者唤醒.他们是否也在等候名单中唤醒所有其他读者?这条线似乎表明他们确实这样做了.这不是每次都有O(n)遍历的风险,并且在写优先级互斥体中冒着雷鸣般的风险吗?
我认为列出设计和实现优化之间的差异很重要。似乎 absl:: 通过提供支持这些设计的实现来优先考虑更好的设计,而不是提供更好的优化组件。有时,更好的设计本质上比笨拙的设计更好,因此结果在两个因素(协同作用)上都得到了优化。Absiel.io 更详细地讨论了这一点。
从他们的来源来看,absl 似乎并没有尝试使用魔法来避免向未决读者广播,因此是的,雷鸣般的羊群仍然是一个问题。一般而言,没有任何实现能够以有意义的方式解决该问题;这是一个设计问题。
通过将条件嵌入为锁的一部分,absl: 确实允许程序员避免或围绕该问题进行设计。仍然有一群人,但锁实现能够减少它的计划 9 点头。如果您设计好唤醒原因,例如掩码中的位,则可以安全地使用共享/独占锁,而不必担心虚假唤醒会影响您的性能。
这是“设计优化”的本质:问题在源代码中得到了更明确的描述,结果实现的质量(性能、缩放等)比其他方式更高。
计划9。条件变量等价于 Unix 内核的睡眠(不是时间)和唤醒的概念。当您检测到某个对象未处于您需要的状态时,您会执行一些操作以开始将其置于该状态,然后等待该状态达到。例如,您可能会在缓存中查找一个对象,当发现它不存在时,创建一个无效的对象并请求使其有效。这允许所有缓存参与者之间存在某种对称性:他们锁定对象,评估或更新其状态,然后同时解锁对象并等待对其进行进一步更改。
丑陋的问题是存在 a: 没有同时发生的事情,以及 b: 锁处理容易出错(我是否持有任何其他锁?这会导致死锁吗?)并且在程序中没有很好地表达。Plan9 的睡眠和唤醒优雅地合并了这些,因此在检查条件时,任何人都不可能影响对象。事实上,参考论文的重点是执行这个简单的合同有多么困难。例如,最好避免多处理环境中的复杂合同。
关键的优化(在 absl: 中)是不需要通过昂贵的上下文切换操作来确定对象处于错误状态,然后返回睡眠。如果选择唤醒您的代码可以验证对象状态是您可能感兴趣的状态,那就更好了。函数调用/方法调用比上下文切换快 100 倍。
Absl 本节讨论如何选择唤醒候选者以及如何剔除牛群。 本节制作广播。
所以前一部分从列表等待者中选择元素,后一部分唤醒它们。如果您查看第 2203 行的 else 条件,它会显示编写器将如何终止列表——w_walk->wake 不正确,并且已设置 wr_wait。此外,如果是写唤醒,则 2015 年和 2023 年的早期测试会阻止构建此列表。
监视器
obj.enter();
while (obj.state != StateIWant) {
obj.wait();
}
...
obj.exit();
Run Code Online (Sandbox Code Playgroud)
需要此线程来执行保护条件。移动这个被阻塞的线程的动作可能是执行条件的成本的 1000 倍。相比之下:
obj.wait(^{return obj.state == StateIWant;});
...
obj.exit();
Run Code Online (Sandbox Code Playgroud)
将允许等待调用在允许等待的任何线程的上下文中评估条件(即调用退出),从而避免在无用情况下进行昂贵的上下文切换。
| 归档时间: |
|
| 查看次数: |
422 次 |
| 最近记录: |