为什么pthread mutex被认为比futex"慢"?

Jas*_*son 40 c linux pthreads futex

为什么POSIX互斥量被认为比futex更重或更慢?pthread互斥锁类型的开销来自哪里?我听说pthread互斥体基于互斥体,当无争议时,不要对内核进行任何调用.那时似乎pthread互斥体只是一个围绕futex的"包装器".

开销只是在函数包装调用中,并且需要互斥函数来"设置"futex(即,基本上是pthread互斥函数调用的堆栈设置)?或者pthread互斥锁是否有一些额外的内存屏障步骤?

nin*_*alj 29

创建Futex是为了提高pthread互斥体的性能.NPTL使用futexes,LinuxThreads早于futexes,我认为这是"慢"考虑的地方.NPTL互斥量可能会有一些额外的开销,但它不应该太多.

编辑: 实际开销主要包括:

  • 为互斥类型选择正确的算法(正常,递归,自适应,错误检查;正常,健壮,优先级继承,优先级保护),其中代码向编译器提示我们可能正在使用普通互斥锁(所以它应该传达给CPU的分支预测逻辑),
  • 如果我们设法接受通常应该快速的互斥锁,那么写入互斥锁的当前所有者,因为它与我们刚刚采用的实际锁定位于同一个缓存行中,除非锁定严重争用和其他一些锁定CPU在我们接受它的时间和我们尝试写入所有者之间访问锁定(对于普通的互斥锁,这种写入是不必要的,但是需要用于错误检查和递归互斥锁).

因此,几个周期(典型情况)到几个周期+分支错误预测+额外的高速缓存未命中(非常坏的情况).

  • @Jason,看作是替换互斥锁,futex并没有给你带来太大的性能差异.相比之下,它有一个更难以捕获的API,所以不要这样做.futex真正有用的地方在于它一次被视为互斥*和*条件变量(在'int`条件下).在那里它有更多的时间和空间效率,你可以避免POSIX的陷阱,有人可以通过使用不同的互斥锁等待条件. (5认同)
  • @Jason:不是真的,除非您正在编写自己的libc,或者想要创建除互斥锁之外的其他同步原语. (2认同)

Dav*_*rtz 14

对您的问题的简短回答是,已知futexes尽可能高效地实现,而pthread互斥体可能是也可能不是.至少,pthread互斥锁具有与确定互斥锁类型相关的开销,而互斥锁则没有.因此,futex几乎总是至少与pthread互斥锁一样有效,除非有人认为某些结构比futex更轻,然后释放一个pthreads实现,将其用于默认的互斥锁.


Mar*_*zer 10

从技术上讲,pthread互斥量并不比futex更慢或更快.pthread只是一个标准API,因此它们是慢还是快取决于该API实现.

特别是在Linux中,pthread互斥体被实现为futexes,因此速度很快.实际上,你不想使用futex API本身,因为它很难使用,在glibc中没有合适的包装函数,并且需要在汇编中进行编码,这是不可移植的.幸运的是,对于我们来说,glibc维护者已经在pthread互斥API的引擎下为我们编写了所有这些代码.

现在,因为大多数操作系统都没有实现futexes,所以程序员通常用pthread mutex来表示你从pthread互斥体的常规实现中获得的性能,这是较慢的.

因此,统计事实是,在大多数符合POSIX标准的操作系统中,pthread互斥体在内核空间中实现,并且比futex慢.在Linux中,它们具有相同的性能.可能有其他操作系统在用户空间中实现了pthread互斥(在非竞争情况下),因此具有更好的性能,但我现在只知道Linux.


Nek*_*ios 7

因为它们尽可能地留在用户空间中,这意味着它们需要更少的系统调用,这本身就更快,因为用户和内核模式之间的上下文切换是昂贵的.

当你谈论POSIX线程时,我假设你正在谈论内核线程.完全可能有一个POSIX线程的完全用户空间实现,它不需要系统调用,但有自己的其他问题.

我的理解是,futex位于内核POSIX线程和用户空间POSIX线程之间.

  • 内核互斥锁在无争议时不会留在用户空间中,而是进入内核模式.POSIX线程的内核实现中的任何线程操作都直接进入内核模式,因为实现中没有用户空间部分. (4认同)
  • 为了使事情变得更复杂(我希望更清楚),仅仅因为你使用'pthreads'或POSIX线程并不意味着你正在使用内核或用户模式实现.事实上我不知道如何确定除了潜水源或实验观察他们的行为. (2认同)