absl :: Mutex的条件关键部分如何处理读取器唤醒

时间:2017-12-24 00:22:11

标签: c++ multithreading synchronization mutex

我想知道最好问一下这样的事情,所以我在Meta(https://meta.stackexchange.com/questions/304981)上提出了这个问题并且被引导到这里,所以这里就是这样。

我真的很好奇谷歌使用absl::Mutexhttps://github.com/abseil/abseil-cpp/blob/master/absl/synchronization/mutex.h)实现条件关键部分时采用了哪种优化方式。特别是我想知道当读者的情况成真时他们如何处理读者唤醒。他们是否也在等候名单中唤醒所有其他读者? This line似乎表示他们确实这样做..每次O(n)遍历的风险是否都没有,并且还有写入优先级互斥体的风险?

1 个答案:

答案 0 :(得分:4)

我认为设定设计和实施优化之间的差异非常重要。似乎absl ::通过提供支持这些设计的实现来优先考虑更好的设计,而不是提供更好的优化组件。有时,更好的设计本质上比笨拙的设计表现更好,因此结果在两个因素(协同作用)上得到优化。 Absiel.io更详细地讨论了这一点。

从他们的来源看来,绝对不会尝试魔法以避免向未决读者广播,因此是的,雷鸣般的群体仍然是一个问题。一般而言,任何实施都无法以有意义的方式解决该问题;这是一个设计问题。

通过将条件作为锁的一部分嵌入,absl:允许程序员避免或设计该问题。仍有一群人,但锁实现能够将其缩小 plan 9 nod here 。如果你设计好觉醒的原因,例如掩码中的位,你可以安全地使用共享/独占锁,而不必担心会影响你的性能的虚假唤醒。

这是“设计优化”的本质:问题在源中更明确地描述,结果实现的质量(性能,缩放......)比其他方式更高。

<强>的Plan9 即可。条件变量等同于unix内核的睡眠概念(不是时间一)和唤醒。当您检测到某个对象未处于您需要的状态时,您会执行一些操作以启动将其置于该状态,然后等待直到达到该状态。例如,您可以在缓存中查找对象,并在发现它不存在时,创建一个无效的对象并请求它变为有效。这允许所有缓存参与者之间存在一种对称性:它们锁定对象,评估或更新其状态,然后同时解锁对象并等待对其进行进一步更改。

丑陋的问题是存在:没有同时发生的事情,而且b:锁定处理容易出错(我是否持有任何其他锁?这会导致死锁吗?)并且在程序中没有很好地表达。 Plan9的睡眠和唤醒优雅地融合了这些,因此在检查条件时,任何人都不可能影响对象。事实上,参考文献的重点是执行这份简单合同有多难。最好避免在多处理环境中使用复杂的合同for example

关键优化(在absl :)中,没有必要通过昂贵的上下文切换操作来确定对象处于错误状态,然后再回到睡眠状态。如果选择唤醒你的代码可以验证对象状态是你可能感兴趣的那个,那就更好了。函数调用/方法调用比上下文切换快100倍。

Absl This section解决了如何选择唤醒候选人以及如何剔除牧群的问题。 This section生成广播。

因此前一部分从列表服务员中选择元素,后一部分将其唤醒。如果您查看第2203行的其他条件,它会显示作者将如何终止列表 - w_walk-&gt; wake不成立,并且已设置wr_wait。此外,2015年和2023年的早期测试会阻止构建此列表,如果它是写入唤醒。

<强>显示器

obj.enter();
while (obj.state != StateIWant) {
    obj.wait();
}
...
obj.exit();

需要此线程执行保护条件。移动该阻塞线程的动作可能是执行条件的成本的1000倍。相反:

obj.wait(^{return obj.state == StateIWant;});
...
obj.exit();

允许等待调用在任何允许等待的线程(即调用exit)的上下文中评估条件,从而避免在无用的情况下进行昂贵的上下文切换。