我想知道同一件事,所以我测量了它。在我的盒子(3.612361 GHz的AMD FX(tm)-8150八核处理器)上,锁定和解锁位于其自己的缓存行中并且已经缓存的未锁定互斥锁,需要47个时钟(13 ns)。
由于两个内核之间的同步(我使用的是CPU#0和#1),我只能在两个线程上每102 ns调用一次锁定/解锁对,因此每51 ns调用一次,由此可以得出结论,大约需要38秒钟ns在线程执行解锁后恢复,下一个线程可以再次锁定它之前。
我用来调查此问题的程序可以在这里找到:https :
//github.com/CarloWood/ai-statefultask-testsuite/blob/b69b112e2e91d35b56a39f41809d3e3de2f9e4b8/src/mutex_test.cxx
请注意,它具有一些针对我的盒子的硬编码值(xrange,yrange和rdtsc开销),因此您可能必须先对其进行试验,然后它才能为您服务。
它在该状态下生成的图形为:
这显示了基准测试在以下代码上运行的结果:
uint64_t do_Ndec(int thread, int loop_count)
{
uint64_t start;
uint64_t end;
int __d0;
asm volatile ("rdtsc\n\tshl $32, %%rdx\n\tor %%rdx, %0" : "=a" (start) : : "%rdx");
mutex.lock();
mutex.unlock();
asm volatile ("rdtsc\n\tshl $32, %%rdx\n\tor %%rdx, %0" : "=a" (end) : : "%rdx");
asm volatile ("\n1:\n\tdecl %%ecx\n\tjnz 1b" : "=c" (__d0) : "c" (loop_count - thread) : "cc");
return end - start;
}
这两个rdtsc调用测量锁定和解锁互斥锁所需的时钟数(我的盒子上rdtsc调用的开销为39个时钟)。第三个asm是一个延迟循环。线程1的延迟循环的大小比线程0的延迟循环的大小小1个计数,因此线程1的速度稍快一些。
在大小为100,000的紧密循环中调用上述函数。尽管该功能对于线程1而言稍快一些,但由于调用了互斥锁,所以两个循环都同步。从图中可以看出这一点,因为对于线程1,为锁定/解锁对测量的时钟数稍大一些,以解决线程1下的循环中较短的延迟。
在上图中,右下角的点是延迟loop_count为150的测量,然后跟随底部的点朝左,每次测量时都会将loop_count减一。当它变为77时,两个线程中每102 ns调用一次该函数。如果随后进一步减少loop_count,则不再可能同步线程,并且互斥锁在大多数时间实际上已开始被锁定,导致执行锁定/解锁所需的时钟量增加。因此,函数调用的平均时间也会增加。因此情节点现在又往右上移。
由此可以得出结论,每50 ns锁定和解锁一个互斥锁对我来说并不是问题。
总而言之,我的结论是,对OP问题的答案是,添加更多的互斥锁会更好,只要它导致较少的争用即可。
尝试将互斥锁锁定得尽可能短。将它们置于循环之外的唯一原因是,如果该循环的循环速度快于每100 ns(或者,希望同时运行该循环的线程数乘以50 ns)或13 ns次循环大小比通过争用得到的延迟更多。
编辑:我现在对该主题有了更多的了解,并开始怀疑我在这里提出的结论。首先,CPU 0和1被证明是超线程的。即使AMD声称有8个真实内核,但肯定会有一些麻烦,因为其他两个内核之间的延迟要大得多(即0和1成对,2和3、4和5以及6和7也是如此) )。其次,实现std :: mutex的方式是,在无法立即获得互斥锁的锁定(这无疑会非常慢)时,它会在实际执行系统调用之前旋转锁定一点。因此,我在这里测量的是绝对最理想的状态,实际上,每次锁定/解锁时,锁定和解锁可能要花费更多的时间。
最重要的是,互斥体是通过原子实现的。为了使内核之间的原子同步,必须锁定内部总线,该总线将冻结相应的高速缓存行几百个时钟周期。在无法获得锁的情况下,必须执行系统调用以使线程进入睡眠状态;这显然非常慢(系统调用的时间约为10毫秒)。通常,这并不是真正的问题,因为该线程无论如何都必须休眠-但这可能是争用较高的问题,其中线程在正常旋转时无法获得锁,因此系统调用也是如此,但是CAN之后不久拿起锁。例如,如果多个线程紧密地锁定和解锁互斥锁,并且每个线程将锁定保持1微秒左右,然后可能会由于不断地进入睡眠状态并再次醒来而大大放慢了速度。同样,一旦一个线程休眠并且另一个线程必须将其唤醒,则该线程必须执行系统调用,并被延迟约10微秒。因此,当另一个线程正在等待内核中的互斥锁解锁时(在旋转时间过长之后),在解锁互斥锁时会发生这种延迟。