pthread互斥量的开销?

31 c++ linux performance mutex pthreads

我正在尝试使C++ API(对于Linux和Solaris)具有线程安全性,以便可以从不同的线程调用其函数,而不会破坏内部数据结构.在我目前的方法中,我使用pthread互斥锁来保护对成员变量的所有访问.这意味着一个简单的getter函数现在可以锁定和解锁互斥锁,我担心这会产生开销,特别是因为API主要用于单线程应用程序,其中任何互斥锁定看起来都是纯粹的开销.

所以,我想问一下:

  • 您是否有使用锁定的单线程应用程序与不使用锁定的单线程应用程序的性能经验?
  • 与例如相比,这些锁定/解锁呼叫的费用是多少.一个简单的"返回this-> isActive"访问bool成员变量?
  • 你知道更好的方法来保护这种变量访问吗?

cme*_*erw 36

所有现代线程实现都可以完全在用户空间中处理无争用的互斥锁(只有几个机器指令) - 只有在存在争用时,库才必须调用内核.

需要考虑的另一点是,如果应用程序没有显式链接到pthread库(因为它是单线程应用程序),它将只获取虚拟pthread函数(根本不执行任何锁定) - 仅当应用程序是多线程的(并链接到pthread库),将使用完整的pthread函数.

最后,正如其他人已经指出的那样,使用互斥锁来保护像isActive这样的东西的getter方法毫无意义 - 一旦调用者有机会查看返回值,该值可能已经被更改(如互斥锁只能锁定在getter方法中.

  • 最后一段不成立:如果你没有在getter中使用互斥锁,调用者可能会得到一个无效值,因为第二个线程可能在创建副本时覆盖了源值_partly_.(好吧,也许在Bools上工作) (21认同)
  • 虽然不是100%可移植的,但我认为任何常规基元(int,bool或float)都可以原子读取,因为大多数平台都能保证它.我支持glibc的手册,其中说"在实践中,你可以假设int和其他不超过int的整数类型都是原子的.你也可以假设指针类型是原子的;这非常方便.这两个都是真的在GNU C库支持的所有机器上,以及我们所知道的所有POSIX系统上." http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_21.html#SEC360 (7认同)
  • 确实你可以原子地读取布尔值 - 问题是如果没有互斥锁,如果bool在一个线程中更新然后在另一个线程中读取,则第二次读取可能会从处理器的数据缓存中获得旧的陈旧值.获取锁会强制处理器使该线程的数据高速缓存无效. (4认同)
  • 问题很深,取决于架构和编译器的许多参数.哪些类型由处理器原子编写?什么对齐可以保证处理器总线和缓存层次结构的原子性?什么是缓存一致性协议?什么是架构实现的内存一致性模型?什么是语言/编译器假设的内存一致性模型?通常,只有在非常强的假设下,对原始类型的读取和/或写入才能解锁 - 最好留给对其硬件和低级软件有深入了解的人. (3认同)

Bil*_*llT 20

"互斥锁需要操作系统上下文切换.这相当昂贵."

  • 在Linux上并非如此,其中互斥体是使用futex'es实现的.正如cmeerw指出的那样,获取无争议(即,尚未锁定)的互斥锁是一些简单指令的问题,并且通常在25纳秒/当前硬件的范围内.

欲了解更多信息: Futex

每个人都应该知道的数字


JDo*_*ner 7

这有点偏离主题,但你似乎是新的线程 - 一方面,只有线程可以重叠的锁定.然后,尽量减少这些地方.此外,不要试图锁定每个方法,而是考虑线程正在做什么(整体)与一个对象,并进行一次调用,并锁定它.尽量让你的锁尽可能高(这再次提高效率,可能/帮助/避免死锁).但锁不会"组合",你必须在心理上至少按线程和重叠的方式对代码进行交叉组织.


jal*_*alf 2

互斥锁需要操作系统上下文切换。那是相当昂贵的。CPU 仍然可以每秒执行数十万次,而不会有太多麻烦,但它比没有互斥体要昂贵得多。将它放在每个变量访问上可能有点矫枉过正。

它也可能不是您想要的。这种暴力锁定往往会导致死锁。

您知道保护此类变量访问的更好方法吗?

设计您的应用程序,以便共享尽可能少的数据。代码的某些部分应该同步,可能使用互斥体,但仅限那些实际需要的部分。通常不是单个变量访问,而是包含必须以原子方式执行的变量访问组的任务。(也许您需要设置is_active标志以及其他一些修改。设置该标志并且不对对象进行进一步更改是否有意义?)

  • 在多线程库中获得正确行为的唯一方法是期望库的用户正确使用它。垃圾邮件锁定人们*可以*滥用的所有内容并不能解决问题或确保正确性。让用户知道什么可以从其他线程调用,什么不可以从其他线程调用,然后仅锁定*那些*方法。 (3认同)
  • 实际上...... IIRC,在最近的Linux上(这是问题的一半)我认为pthread_mutex_lock大多数时候不需要上下文切换,因为它们是围绕futexes实现的(参见http://en.wikipedia.org/wiki/ Futex )默认情况下。 (3认同)