Windows API提供了关键部分,在这些部分中,等待线程将在上下文切换之前旋转有限次数,但仅限于多处理器系统。这些是使用InitializeCriticalSectionAndSpinCount实现的。 (参见http://msdn.microsoft.com/en-us/library/ms682530.aspx。)当你的关键部分通常只能在短时间内被锁定时,这是有效的,因此争用不应该立即触发上下文切换。两个相关问题:
synchronized
块的实现,在触发上下文切换是一个很好的默认值之前,是否有少量旋转?编辑:当然,没有旋转计数对所有情况都是最佳的。我只对使用非零旋转计数是否更好的默认值而不是使用一个非常感兴趣。
答案 0 :(得分:3)
我的观点是,最佳应用程序性能的最佳“自旋计数”太依赖于硬件,因为它是跨平台API的重要组成部分,您应该只使用互斥锁(在posix中,{{ 1}} / pthread_mutex_init
/ destroy
/ lock
)或自旋锁(trylock
/ pthread_spin_init
/ destroy
/ lock
)。基本原理如下。
旋转计数有什么意义?基本上,如果锁所有者与尝试获取锁的线程同时运行,那么锁所有者可能会足够快地释放锁,以致EnterCriticalSection调用者可以避免在获取锁时放弃CPU控制,提高该线程的性能,并避免上下文切换开销。两件事:
1:显然这取决于锁所有者并行运行尝试获取锁的线程。这在单个执行核心上是不可能的,这几乎可以肯定微软在这样的环境中将计数视为0。即使有多个内核,当另一个线程尝试获取锁时,锁拥有者很可能没有运行,在这种情况下,最佳旋转计数(对于该尝试)仍为0。
2:同时执行时,最佳旋转计数仍依赖于硬件。不同的处理器将花费不同的时间来执行类似的操作。它们有不同的指令集(我最常用的ARM没有整数除法指令),不同的高速缓存大小,操作系统在内存中会有不同的页面...减少旋转计数可能会花费不同的时间加载 - 存储体系结构,而不是算术指令可以直接访问内存的体系结构。即使在同一处理器上,相同的任务也会花费不同的时间,具体取决于(至少)内存缓存的内容和组织。
如果同时执行的最佳旋转计数是无限的,那么trylock
函数应该完成你所追求的。如果不是,则使用pthread_spin_*
函数。
答案 1 :(得分:0)
对于高级跨平台线程库或者 同步块的实现,是少量的 在触发上下文切换之前旋转一个好的默认值?
有人会这么认为。许多月以前,Solaris 2.x实现了自适应锁定,如果互斥锁由另一个CPU上执行的线程或其他块阻塞,则会旋转一段时间 - 旋转一段时间。
显然,在单CPU系统上旋转是没有意义的。