[英]Spin Lock Implementations (OSSpinLock)
我刚刚开始研究多线程编程和线程安全性。 我熟悉忙碌等待,经过一些研究后,我现在熟悉自旋锁背后的理论,所以我想我会看一下OSSpinLock在Mac上的实现。 它归结为以下函数(在objc-os.h中定义):
static inline void ARRSpinLockLock(ARRSpinLock *l)
{
again:
/* ... Busy-waiting ... */
thread_switch(THREAD_NULL, SWITCH_OPTION_DEPRESS, 1);
goto again;
}
( 完全实施 )
在做了一些挖掘之后,我现在已经大致了解了thread_switch
的参数是什么( 这个站点是我发现它的地方)。 我对我所读到的内容的解释是,对thread_switch的这一特定调用将切换到下一个可用线程,并将当前线程的优先级降低到1个周期的绝对最小值。 '最终'(在CPU时间内)此线程将再次变为活动状态并立即再次执行goto again;
重新开始忙碌等待的指令。
我的问题是,为什么这个电话实际上是必要的? 我发现了一个自旋锁的另一种实现方式(适用于Windows这段时间), 在这里 ,它不包括(Windows的当量)的线程切换调用的。
您可以通过多种不同方式实现自旋锁。 如果您找到另一个针对Windows的SpinLock
实现,您将看到另一种算法(它可能涉及SetThreadPriority
, Sleep
或SwitchToThread
)。
ARRSpinLockLock
默认实现非常聪明,在第一个旋转周期后,它“ ARRSpinLockLock
”一段时间的线程优先级,这具有以下优点:
NOP
或PAUSE
。 Windows实现不会这样做,因为Windows API不提供该机会(没有等效的thread_switch()
函数,并且对SetThreadPriority
多次调用可能效率较低)。
我实际上并不认为他们是那么不同。 在第一种情况下:
static inline void ARRSpinLockLock(ARRSpinLock *l)
{
unsigned y;
again:
if (__builtin_expect(__sync_lock_test_and_set(l, 1), 0) == 0) {
return;
}
for (y = 1000; y; y--) {
#if defined(__i386__) || defined(__x86_64__)
asm("pause");
#endif
if (*l == 0) goto again;
}
thread_switch(THREAD_NULL, SWITCH_OPTION_DEPRESS, 1);
goto again;
}
我们试图获得锁定。 如果失败了,我们在for
循环中旋转,如果它在此期间可用,我们会立即尝试重新获取它,如果不是,我们放弃CPU。
在另一种情况下:
inline void Enter(void)
{
int prev_s;
do
{
prev_s = TestAndSet(&m_s, 0);
if (m_s == 0 && prev_s == 1)
{
break;
}
// reluinquish current timeslice (can only
// be used when OS available and
// we do NOT want to 'spin')
// HWSleep(0);
}
while (true);
}
请注意if
下面的注释,它实际上表示如果操作系统为我们提供该选项,我们可以旋转或放弃CPU。 事实上,第二个例子似乎只是让那个部分留给程序员[插入你在这里继续代码的首选方式],所以从某种意义上说它不像第一个那样完整的实现。
我对整个事情的看法,我正在评论第一个片段,就是他们试图在能够快速获得锁定(1000次迭代)和不过多地占用CPU之间取得平衡(因此我们如果锁不可用,最终会切换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.