【发布时间】:2012-03-08 16:35:05
【问题描述】:
// SubFetch(x,y) = atomically x-=y and return x (__sync_sub_and_fetch)
// AddFetch(x,y) = atomically x+=y and return x (__sync_add_and_fetch)
// CompareWait(x, y) = futex(&x, FUTEX_WAIT, y) wait on x if x == y
// Wake(x, y) = futex(&x, FUTEX_WAKE, y) wake up y waiters
struct Lock
{
Lock() : x(1) {}
void lock()
{
while (true)
{
if (SubFetch(x, 1) == 0)
return;
x = -1;
CompareWait(x, -1);
}
}
void unlock()
{
if (AddFetch(x, 1) == 1)
return;
x = 1;
Wake(x, 1);
}
private:
int x;
};
Linux 3.0 提供了一个名为 futex 的系统调用,许多并发实用程序都基于该调用,包括最近的 pthread_mutex 实现。每当您编写代码时,您都应该始终考虑使用现有实现还是自己编写代码是您项目的更好选择。
上面是一个基于futex和man futex(7)中语义描述的Lock(互斥量,1个允许计数信号量)的实现
它似乎包含一个死锁错误,在多个线程尝试锁定和解锁它几千次后,线程可能会进入 x == -1 并且所有线程都卡在 CompareWait 中的状态,但是没有人正在持有锁。
任何人都可以看到错误在哪里吗?
更新:我有点惊讶 futex(7)/semantics 如此糟糕。我完全重写了Lock如下......现在这样正确吗?
// CompareAssign(x,y,z) atomically: if (x == y) {x = z; ret true; } else ret false;
struct Lock
{
Lock() : x(0) {}
void lock()
{
while (!CompareAssign(x, 0, 1))
if (x == 2 || CompareAssign(x, 1, 2))
CompareWait(x, 2);
}
void unlock()
{
if (SubFetch(x, 1) == 0)
return;
x = 0;
Wake(x, 1);
}
private:
int x;
};
这里的想法是x有以下三种状态:
0: unlocked
1: locked & no waiters
2: locked & waiters
【问题讨论】:
-
我听说 futexes 看起来很简单,很难正确使用它们。你这样做有什么理由吗?
-
嗯? pthread_mutex 有什么问题?
-
futex sematic “这么破”是什么意思。它是用户空间原子操作和基于内核的线程等待和信号之间的接口。实现这一点并非常有效地做到这一点是微不足道的。它并不意味着是应用程序级编程 API。
-
正如 futex 文档所述,它会受到虚假唤醒的影响,您是否检查并正确处理 EINTR ?
-
@JensGustedt:我的意思是 futex(7)/“语义”部分中的实现描述不正确并且充满了竞争条件。您的其余评论无关紧要。
标签: c++ c linux concurrency futex