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,则其内容描述等待的最小持续时间,否则为无限期。参数 uaddr2val3 被忽略。

对于 futex(7),如果递减计数导致负值(指示竞争),则执行此调用,并将休眠直到另一个进程释放 futex 并执行 FUTEX_WAKE 操作。

FUTEX_WAKE
此操作唤醒最多 val 个等待此 futex 地址上的进程(即,在 FUTEX_WAIT 内部)。参数 timeoutuaddr2val3 被忽略。

对于 futex(7),如果递增计数显示存在等待者,并且 futex 值已设置为 1(指示它可用),则执行此操作。

FUTEX_FD(存在于 Linux 2.6.25 及更早版本中)
为了支持异步唤醒,此操作将文件描述符与 futex 关联起来。如果另一个进程执行 FUTEX_WAKE,则该进程将收到在 val 中传递的信号编号。调用进程在使用后必须关闭返回的文件描述符。参数 timeoutuaddr2val3 被忽略。

为了防止竞争条件,调用者应测试 FUTEX_FD 返回后 futex 是否已递增。

由于它本质上存在竞争,FUTEX_FD 已从 Linux 2.6.26 及更高版本中删除。

FUTEX_REQUEUE(自 Linux 2.5.70 起)
引入此操作是为了避免在 FUTEX_WAKE 使用时出现“雷鸣蜂群”效应,并且所有唤醒的进程都需要获取另一个 futex。此调用唤醒 val 个进程,并将所有其他等待者重新排队到地址为 uaddr2 的 futex 上。参数 timeoutval3 被忽略。
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
opFUTEX_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 在

引用自

clone(2), eventfd(2), futex(4), get_robust_list(2), prctl(2), pthreads(7), set_tid_address(2)