gpt4 book ai didi

multithreading - 对自旋锁感到困惑

转载 作者:行者123 更新时间:2023-12-04 06:49:20 26 4
gpt4 key购买 nike

我读自旋锁代码from here ,尤其是这部分

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);
}

为什么我们需要测试两个条件 m_s == 0 && prev_s == 1?我认为只需测试 prev_s == 1 就足够了。有什么想法吗?

编辑:版本 2。如果有错误,我们应该以这种方式修复吗?

inline void Enter(void)
{
do
{
if (m_s == 0 && 1 == TestAndSet(&m_s, 0))
{
break;
}
// reluinquish current timeslice (can only
// be used when OS available and
// we do NOT want to 'spin')
// HWSleep(0);
}
while (true);
}

编辑:版本 3。我认为功能级别的版本 3 是正确的,但性能不够好,因为每次我们都需要写入,没有提前读取测试。我的理解正确吗?

inline void Enter(void)
{
do
{
if (1 == TestAndSet(&m_s, 0))
{
break;
}
// reluinquish current timeslice (can only
// be used when OS available and
// we do NOT want to 'spin')
// HWSleep(0);
}
while (true);
}

@dragonfly,这是我的 bug 修复版本 4(修复了你指出的版本 2 中的一个 bug),请你看看它是否正确?谢谢!

编辑:版本 4。

inline void Enter(void)
{
do
{
if (m_s == 1 && 1 == TestAndSet(&m_s, 0))
{
break;
}
// reluinquish current timeslice (can only
// be used when OS available and
// we do NOT want to 'spin')
// HWSleep(0);
}
while (true);
}

最佳答案

在我看来,这是一次尝试优化的尝试,出了点小问题。我怀疑它正在尝试“TATAS”——“测试和测试和设置”,如果它看到锁已经被占用,它甚至不会尝试执行 TestAndSet。

post about spin locks for .NET 中, Joe Duffy 将此 TATAS 代码写为:

class SpinLock {
private volatile int m_taken;

public void Enter() {
while (true) {
if (m_taken == 0 &&
Interlocked.Exchange(ref m_taken, 1) == 0)
break;
}
}

public void Exit() {
m_taken = 0;
}
}

(请注意,Joe 使用 1 表示已锁定,使用 0 表示未锁定,这与代码项目示例不同 - 两者都可以,只是不要混淆两者!)

请注意,此处对 Interlocked.Exchange 的调用m_taken 为 0 为条件。这减少了争用——相对昂贵的(我猜)测试和设置操作被避免了,这是不必要的。我怀疑这就是作者的目的,但没有完全正确。

Wikipedia article about spinlocks 中也提到了这一点在“重大优化”下:

To reduce inter-CPU bus traffic, when the lock is not acquired, the code should loop reading without trying to write anything, until it reads a changed value. Because of MESI caching protocols, this causes the cache line for the lock to become "Shared"; then there is remarkably no bus traffic while a CPU is waiting for the lock. This optimization is effective on all CPU architectures that have a cache per CPU, because MESI is so ubiquitous.

“循环读取”正是 while 循环所做的 - 直到它看到 m_taken 发生变化,它才会读取。当它看到变化时(即当锁被释放时),它会再次锁定。

当然,我很可能遗漏了一些重要的东西 - 像这样的问题非常微妙。

关于multithreading - 对自旋锁感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/688785/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com