futex(2) - Linux 手册页
名称
futex - 快速用户空间锁
概要
#include <linux/futex.h> #include <sys/time.h> int futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3);
描述
futex() 系统调用提供了一种方法,用于程序等待给定地址处的值发生变化,以及唤醒任何等待特定地址上的进程的方法(虽然在不同进程中相同内存的地址可能不相等,但内核会在内部映射它们,因此在 futex() 调用中映射在不同位置的相同内存将对应起来)。此系统调用通常用于实现共享内存中锁的竞争情况,如 futex(7) 中所述。
当 futex(7) 操作在用户空间中未无竞争地完成时,需要调用内核进行仲裁。仲裁可以意味着将调用进程置于睡眠状态,或者相反,唤醒一个等待的进程。
调用此函数的程序预计将遵守 futex(7) 中规定的语义。由于这些语义涉及编写不可移植的汇编指令,因此这可能意味着大多数用户实际上是库作者,而不是通用应用程序开发人员。
uaddr 参数需要指向一个对齐的整数,该整数存储计数器。要执行的操作通过 op 参数传递,以及一个值 val。
当前定义了五种操作
- FUTEX_WAIT
- 此操作会原子地验证 futex 地址 uaddr 是否仍然包含值 val,并等待此 futex 地址上的 FUTEX_WAKE。如果 timeout 参数不为 NULL,则其内容描述等待的最小持续时间,否则为无限期。参数 uaddr2 和 val3 被忽略。
对于 futex(7),如果递减计数导致负值(指示竞争),则执行此调用,并将休眠直到另一个进程释放 futex 并执行 FUTEX_WAKE 操作。
- FUTEX_WAKE
- 此操作唤醒最多 val 个等待此 futex 地址上的进程(即,在 FUTEX_WAIT 内部)。参数 timeout、uaddr2 和 val3 被忽略。
对于 futex(7),如果递增计数显示存在等待者,并且 futex 值已设置为 1(指示它可用),则执行此操作。
- FUTEX_FD(存在于 Linux 2.6.25 及更早版本中)
- 为了支持异步唤醒,此操作将文件描述符与 futex 关联起来。如果另一个进程执行 FUTEX_WAKE,则该进程将收到在 val 中传递的信号编号。调用进程在使用后必须关闭返回的文件描述符。参数 timeout、uaddr2 和 val3 被忽略。
为了防止竞争条件,调用者应测试 FUTEX_FD 返回后 futex 是否已递增。
由于它本质上存在竞争,FUTEX_FD 已从 Linux 2.6.26 及更高版本中删除。
- FUTEX_REQUEUE(自 Linux 2.5.70 起)
- 引入此操作是为了避免在 FUTEX_WAKE 使用时出现“雷鸣蜂群”效应,并且所有唤醒的进程都需要获取另一个 futex。此调用唤醒 val 个进程,并将所有其他等待者重新排队到地址为 uaddr2 的 futex 上。参数 timeout 和 val3 被忽略。
- FUTEX_CMP_REQUEUE(自 Linux 2.6.7 起)
- 在 FUTEX_REQUEUE 的预期用途中存在竞争,因此引入了 FUTEX_CMP_REQUEUE。这类似于 FUTEX_REQUEUE,但首先检查位置 uaddr 是否仍然包含值 val3。如果不是,则操作将以错误 EAGAIN 失败。参数 timeout 被忽略。
返回值
如果发生错误,所有操作都返回 -1,并设置 errno 以指示错误。成功的返回值取决于操作,如下列表所述
- FUTEX_WAIT
- 如果进程被 FUTEX_WAKE 调用唤醒,则返回 0。有关各种可能的错误返回值,请参阅 ERRORS。
- FUTEX_WAKE
- 返回唤醒的进程数。
- FUTEX_FD
- 返回与 futex 关联的新文件描述符。
- FUTEX_REQUEUE
- 返回唤醒的进程数。
- FUTEX_CMP_REQUEUE
- 返回唤醒的进程数。
错误
- EACCES
无法读取 futex 内存。
EAGAIN
FUTEX_CMP_REQUEUE 检测到 uaddr 指向的值不等于预期值 val3。(这可能表示竞争;现在使用安全的 FUTEX_WAKE。)
EFAULT
无法从用户空间检索 timeout 信息。
EINTR
FUTEX_WAIT 操作被信号(参见 signal(7))或虚假唤醒中断。
EINVAL
无效的参数。
ENFILE
已达到系统打开文件总数的限制。
ENOSYS
op 中指定的无效操作。
- ETIMEDOUT
- FUTEX_WAIT 操作超时。
- EWOULDBLOCK
- op 是 FUTEX_WAIT,并且在调用时,uaddr 指向的值不等于预期的值 val。
版本
最初的 futex 支持合并在 Linux 2.5.7 中,但语义与上述描述不同。在 Linux 2.5.40 中引入了一个具有此页面中描述的语义的 4 参数系统调用。在 Linux 2.5.70 中添加了一个参数。在 Linux 2.6.7 中添加了第六个参数——尤其是在 s390 架构上,这非常混乱。
符合
此系统调用是 Linux 特有的。
说明
再次重申,裸 futex 并非旨在作为最终用户的易于使用的抽象。 (glibc 中没有此系统调用的包装函数。)预计实现者精通汇编语言,并且已阅读下面参考的 futex 用户空间库的源代码。
参见
futex(7)
Fuss, Futexes and Furwocks: Fast Userlevel Locking in Linux(2002 年渥太华 Linux 研讨会论文集),在线地址:
Futex 示例库,futex-*.tar.bz2 在