什么是PTHREAD_MUTEX_ADAPTIVE_NP

在哪里可以找到“自适应”pthread互斥锁的文档? 符号PTHREAD_MUTEX_ADAPTIVE_NP是在我的系统上定义的,但我在网上找到的唯一文档没有说明自适应互斥锁是什么,或者什么时候适合使用。

那么……它是什么,我什么时候应该使用它?

作为参考,我的libc版本是:

GNU C Library (Ubuntu EGLIBC 2.15-0ubuntu10.5) stable release version 2.15, by Roland McGrath et al. Copyright (C) 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 4.6.3. Compiled on a Linux 3.2.50 system on 2013-09-30. Available extensions: crypt add-on version 2.1 by Michael Glad and others GNU Libidn by Simon Josefsson Native POSIX Threads Library by Ulrich Drepper et al BIND-8.2.3-T5B libc ABIs: UNIQUE IFUNC For bug reporting instructions, please see: . 

和“uname -a”给出

 Linux desktop 3.2.0-55-generic #85-Ubuntu SMP Wed Oct 2 12:29:27 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux 

你去吧 当我读到它时,它是一个非常简单的互斥体,除了使无争用情况快速运行之外,它不关心任何事情。

PTHREAD_MUTEX_ADAPTIVE_NP是我在担任glibc贡献者的角色时发明的,它使LinuxThreads更可靠,性能更好。 LinuxThreads是glibc的NPTL库的前身,最初是由Xavier Leroy开发的独立库,Xavier Leroy也是OCaml的创建者之一。

自适应互斥体以基本上未修改的forms存活到NTPL中:代码几乎相同,包括估计器平滑的魔术常数和相对于估计器的最大旋转。

在SMP下,当您获取互斥锁并看到它被锁定时,简单地放弃并调用要阻塞的内核可能是次优的。 如果锁的所有者只持有几个指令的锁,那么等待执行那些指令然后通过primefaces操作获取锁是更便宜的,而不是通过进行系统调用来花费数百个额外的周期。 。

内核开发人员非常了解这一点,这也是我们在Linux内核中为快速关键部分提供自旋锁的原因之一。 (其他原因当然是,无法hibernate的代码,因为它处于中断上下文中,可以获取自旋锁。)

问题是,你要等多久? 如果你永远旋转直到获得锁定,那么这可能是次优的。 用户空间程序编写得不像内核代码(咳嗽)。 他们可能有很长的关键部分。 他们也不能禁用先发制人; 由于上下文切换,有时关键部分会爆炸。 (POSIX线程现在提供实时工具来处理这个问题:您可以将线程放入实时优先级和FIFO调度等,并配置处理器关联性。)

我认为我们尝试了固定的迭代计数,但后来我有了这个想法:我们为什么要猜测,何时可以衡量。 为什么我们不实现锁定持续时间的平滑估计,类似于我们对TCP重传超时(RTO)估计器所做的。 每次我们旋转一个锁,我们应该测量它实际获取它所需的旋转次数。 而且,我们不应该永远旋转:我们应该最多旋转两倍于当前估计值。 当我们进行测量时,我们可以在几条指令中以指数方式平滑它:获取前一个值的一小部分和新值的一小部分,并将它们加在一起,这与将它们的差异的一小部分添加到后面相同到估算器:比如, estimator += (new_val - estimator)/8表示旧值和新值之间的1/8到7/8混合。

您可以将其视为监督者。 假设估算器告诉您锁定平均需要80次旋转才能获得。 你可以非常自信,如果你已经执行了160次旋转,那么就会出现问题:锁的所有者正在执行一些特别长的情况,或者可能遇到了页面错误或以其他方式被抢占。 此时,等待线程会减少其损失并调用内核来阻止。

如果没有测量,你就无法准确地做到这一点:没有“一刀切”的价值。 比方说,在一个程序中,200个旋转的固定限制将是次优的,其关键部分非常短,以至于在仅等待10次旋转之后几乎总是可以获取锁定。 每次存在exception等待时间时,互斥锁定function将烧掉200次迭代,而不是很好地放弃,比如20和保存周期。

这种自适应方法是专用的,因为它不适用于所有程序中的所有锁,因此它被打包为特殊的互斥锁类型。 例如,对于长时间锁定互斥锁的程序来说,它不会很好地工作:这段时间太长,以至于在大的估计值上浪费了比进入内核时更多的CPU时间。 该方法也不适用于单处理器:除了试图获取锁定的线程之外的所有线程都被挂起在内核中。 这种方法也不适用于公平很重要的情况:它是机会主义的锁定。 无论有多少其他线程在等待,无论多长时间,或者它们的优先级是什么,新线程都可以出现并抢夺锁定。

如果您的代码表现非常好,而且关键部分很短,并且您希望在SMP上获得更好的性能,那么自适应互斥锁可能值得一试。

在那里提到了这个符号:

http://elias.rhi.hi.is/libc/Mutexes.html

“LinuxThreads仅支持一个互斥锁属性:互斥锁类型,”快速“互斥锁为PTHREAD_MUTEX_ADAPTIVE_NP,”递归“互斥锁为PTHREAD_MUTEX_RECURSIVE_NP,”定时“互斥锁为PTHREAD_MUTEX_TIMED_NP,”错误检查“互斥锁为PTHREAD_MUTEX_ERRORCHECK_NP。如NP后缀所示,这是POSIX标准的非便携式扩展,不应用于便携式程序。

互斥锁类型确定当线程尝试使用pthread_mutex_lock锁定已拥有的互斥锁时会发生什么。 如果互斥锁是“快速”类型,则pthread_mutex_lock将永远挂起调用线程。 如果互斥锁属于“错误检查”类型,则pthread_mutex_lock会立即返回错误代码EDEADLK。 如果互斥锁是“递归”类型,则对pthread_mutex_lock的调用会立即返回成功返回码。 拥有互斥锁的线程锁定它的次数记录在互斥锁中。 拥有线程必须在互斥锁返回解锁状态之前调用pthread_mutex_unlock相同的次数。

默认的互斥锁类型是“定时”,即PTHREAD_MUTEX_TIMED_NP。“

编辑:更新了jthill发现的信息(谢谢!)

有关互斥锁标志和PTHREAD_MUTEX_ADAPTIVE_NP的更多信息,请访问 :

“PTHRED_MUTEX_ADAPTIVE_NP是一种新的互斥体,旨在牺牲公平性甚至CPU周期来实现高吞吐量。这种互斥体不会将所有权转移到等待的线程,而是允许竞争。此外,通过SMP内核,锁定操作使用旋转来重新锁定,以避免立即解除锁定的成本。“

这基本上建议如下:在需要高吞吐量的情况下,可以实现这样的互斥锁,因为它本质上需要线程逻辑的额外考虑。 您必须设计一种可以使用这些属性的算法,从而实现高吞吐量。 从内部负载平衡的东西(而不是“来自内核”),其中执行顺序并不重要。

有一本非常好的linux / unixmultithreading编程书,这个名字让我感到惊讶。 如果我发现它我会更新。