登录/注册

futex

更多

好的,我们来详细解释一下 Futex(快速用户空间互斥锁)

核心概念

Futex(Fast Userspace muTEX)是 Linux 内核提供的一种基础同步原语,主要用于在用户空间实现高效的(如互斥锁 Mutex、信号量 Semaphore)和线程同步机制(如条件变量 Condition Variable)。

设计目标:解决什么问题?

在 Futex 出现之前,用户空间线程同步主要依赖于纯用户空间的锁(容易导致忙等待,浪费 CPU)或完全依赖昂贵的系统调用(如 semop)。这两种方式在高竞争场景下性能都不理想:

  1. 纯用户空间锁(忙等待): 一个线程尝试获取已被占用的锁时,会不停循环检查锁状态(忙等待)。这非常浪费 CPU 资源,尤其是在锁被长时间持有时。
  2. 纯内核锁: 每次加锁、解锁操作都要陷入内核态执行系统调用。系统调用的开销(上下文切换)非常大,会显著降低性能,尤其在锁争用不激烈时,这种开销显得更不必要。

Futex 的设计目标就是解决这个矛盾:

简单来说,Futex 通过只在真正需要内核介入时才调用内核,极大优化了用户空间锁的性能。

工作原理(简化模型)

可以把 Futex 想象成一个基于内核辅助的用户空间等待队列。它依赖于两个组成部分:

  1. 用户空间原子变量(Futex Word):

    • 这是一个在进程内所有线程共享的内存地址(通常是一个 32 位整数)。
    • 它的值代表了锁的状态(例如,0 表示空闲,线程ID 表示被某个线程持有,或其他自定义状态)。
    • 对这个变量的基本操作(检查值、比较并交换 - Compare-and-Swap)必须使用原子指令(如 __sync_val_compare_and_swap)来完成,以保证线程安全。
  2. 内核的等待队列管理:

    • 内核为每个 Futex Word 维护一个(隐式的)等待队列。
    • 提供了两个核心的系统调用(或封装它们的库函数,如 futex):
      • FUTEX_WAIT (int *uaddr, int val): 检查用户空间地址 uaddr 处的值是否仍然等于 val如果相等,说明锁仍然不可用(或者条件仍未满足),那么调用线程将自己挂起(睡眠)在 uaddr 对应的内核等待队列上,让出 CPU如果不相等(说明值在检查前已被其他线程改变,锁可能已可用或条件已满足),则立即返回,避免不必要的睡眠。
      • FUTEX_WAKE (int *uaddr, int n): 唤醒最多 n 个(通常是 1 个或多个)在 uaddr 对应的内核等待队列上睡眠的线程。

工作流程示例(以 Mutex 锁为例)

  1. 尝试加锁(用户空间):
    • 线程使用原子操作尝试将 Futex Word 的值从 0(空闲)改成自己的线程 ID(或 1 表示锁定)。如果成功,说明获取锁成功!整个过程没有系统调用
  2. 加锁失败(遇到竞争):
    • 如果原子操作失败(当前值不是 0,已被其他线程锁定),线程需要等待。
    • 线程调用 FUTEX_WAIT(uaddr, expected_val)。这里的 expected_val 就是它刚刚看到的那个非 0 值(比如其他线程的 ID 或 1)。
    • FUTEX_WAIT 系统调用内部:
      • 内核首先再次检查 *uaddr 是否还是等于 expected_val
      • 如果不再是 expected_val(例如,持有锁的线程可能恰好在此时释放了锁),系统调用立即返回 EWOULDBLOCK(或其他指示需要重试的值),线程回到用户空间重新尝试步骤 1(乐观重试)。
      • 如果还是 expected_val,内核将线程放入 uaddr 对应的等待队列,并将其挂起(睡眠)。
  3. 释放锁并唤醒(用户空间 + 内核):
    • 持有锁的线程完成操作后,首先使用原子操作将 Futex Word 的值重置回 0(释放锁)。
    • 然后,它知道可能有线程在等待这个锁,它会调用 FUTEX_WAKE(uaddr, 1)
    • FUTEX_WAKE 系统调用: 内核从 uaddr 对应的等待队列中唤醒一个(或指定数量 n 个)睡眠的线程。
  4. 被唤醒线程(用户空间):
    • 被内核唤醒的线程从 FUTEX_WAIT 系统调用中返回。
    • 不会直接获得锁!它只是知道锁的状态 可能 发生了变化(被释放了)。它必须回到步骤 1,再次尝试使用原子操作去获取锁(因为可能有多个被唤醒的线程,或者可能有新来的线程也在竞争)。它可能成功,也可能失败(发生新的竞争),如果失败则再次进入 FUTEX_WAIT

关键点

主要用途

Futex 是底层机制。我们一般不直接使用原始的 futex 系统调用编程,而是使用基于它构建的高级同步对象:

总结

Futex 是 Linux 高性能线程同步的基石。它通过结合用户空间的原子操作按需的内核等待队列管理,巧妙地平衡了性能(无竞争时避免系统调用)和资源利用率(竞争时避免忙等待),使得在其基础上构建的各种高级锁(如 Mutex)和同步机制(如条件变量)在高并发程序中能够表现出色。理解 Futex 有助于理解 Linux 多线程程序的性能特性和调试复杂的并发问题。

官方的Debian镜像无法启动怎么解决?

max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns[ 1.376700] futex hash table entries: 2048

2026-02-03 06:41:43

nuc980不管如何都是开不起来kernel panic是怎么回事?

, max_idle_ns: 19112604462750000 ns futex hash table entries: 256 (order: -1, 3072 bytes) pinctrl core

2023-06-13 08:19:57

分析unidbg(unidbgMutil)多线程机制

由于在工作中遇到了某翻译so中有多线程调用,因此使用unidbg分析(基于unidbgMutilThread)并增加阻塞唤醒机制(futex系统调用),但仍未调用成功

2023-05-20 17:23:27

什么是futexFutex用户和内核空间接口API是什么?

编者按:对于Linux系统编程来说,竞争和同步是绕不开的话题。之前分享过Java的对象锁,有读者说自己不做Java不太能理解,这次分享Linux中很基础的同步机制:futex,内容包括基本接口定义和对于优先级反转的处理,希望对大家的技术成长有帮助。

2023-05-20 16:56:49

LoongArch 系统调用 ABI

__NR_unshare 97 ​ /* kernel/futex.c */ #define __NR_futex 98 #define __NR_set_robust_list 99 #define

2023-04-22 21:07:01

鸿蒙内核实现用户态快速互斥锁Futex设计资料合集

Futex(Fast userspace mutex,用户态快速互斥锁),系列篇简称 快锁 ,是一个在 Linux 上实现锁定和构建高级抽象锁如信号量和POSIX互斥的基本工具,它第一次出现在

2022-03-23 14:12:41

imx6q使用官方的mfgtool刷机后启动黑屏是为什么?

] Bus freq driver module loaded[ 0.341097] futex hash table entries: 1024 (order: 4, 65536 bytes

2022-01-10 07:23:35

【HarmonyOS HiSpark IPC DIY Camera试用连载 】liteos-a启动流程概述

) {return ret; }#endif ret = OsFutexInit(); if (ret != LOS_OK) {PRINT_ERR("Create futex failed : %d

2020-11-07 14:45:27

详细解析,嵌入式Linux实现实时化技术过程

和nanosleep精度由具体硬件所能提供的精度决定,使得getTImeofday能够提供实时系统所需的精确时间值。 ● 其他改进  Linux在用户层支持性能良好的futex,实现原理类似于内核

2020-04-30 09:00:54

am437更换内核无法启动

: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns[ 0.072151] futex hash table entries: 256

2020-01-14 10:39:02
7天热门专题 换一换
相关标签