在实践中,信号量与自旋锁相比有多昂贵?

Joh*_*tte 5 performance multithreading semaphore real-time

这个问题询问是否可以以不影响延迟但使用更少 CPU 时间的方式改进自旋锁。大量答案表明了 C++11、Boost 等高级语言概念。

我的第一个想法是使用一个简单的 C 信号量,因为只有当缓冲区为空或已满时,海报才需要阻塞。

然而,在写答案的过程中,我意识到我不知道这些函数在实践中的开销是多少。直觉上,它似乎应该很小,而且对我来说从来都不是优化问题,但与自旋锁相比,它可能是很大的。据推测它也依赖于系统。

这个问题的答案表明,当锁定少于一个线程量子时,自旋锁是首选,但没有给出实际原因说明原因。

这个问题的答案提供了 C++ 中信号量实现的工作示例,该示例在主体中使用带有 pthread_wait 的自旋锁,但它并非取自任何实际的语言实现。

这里,一些人认为有关互斥锁和信号量之间的速度差异的问题是微不足道的。其他人说信号量速度较慢。

此问题链接的一篇文章表明,在 2.4GhZ 机器上,互斥锁的 C# 锁定命令实际上需要 50 纳秒(因此大约 100 个周期)。然而,尚不清楚 C# 的实现是否代表 POSIX 信号量的直接 C 实现。

所以,问题是,在实践中信号量使用的开销是多少,并且通过扩展,如果我关心的是延迟(即由于某种原因而不是可维护性),我什么时候应该更喜欢自旋锁?

Mor*_*ner 2

我绝不是这方面的专家,因此您应该根据您的情况对我的建议持保留态度。

自旋锁是使用本质上是原子的处理器指令来实现的。因此,获取和释放锁可以非常快。持有锁的时间越长,锁的争用越多,性能就会从理想状态下降。因此,它最适合不经常更新的数据。Afaik .NET (4.0+) 有自己的仅托管自旋锁实现,可以避免转换为非托管代码(以及后续的内核访问),这使得开销几乎微不足道。

几乎所有其他锁类型都基于 WaitHandles(无论如何,在 .NET 领域,例外是仅托管的 Monitor 类),除非您正在编写在内核空间中运行的设备驱动程序,否则性能可能不会变化太多(因为很大一部分成本是进入内核空间并返回)。选择最适合您的应用需求的锁类型。

如果您真的非常关心它,请将一些模拟预期工作负载的性能测试放在一起,并对您的首选选项进行基准测试,看看它们的表现如何。