步骤 6 / 9
抢不到怎么办:futex 让线程睡一会
抢不到锁时,线程通过 futex 系统调用请内核让自己睡眠,锁释放后再被唤醒。
一直空转重试(自旋)浪费 CPU,所以 Linux 的 pthread_mutex 抢不到时会调用 futex,让内核把线程挂起。 线程 1 解锁时,如果发现有人在等,就再调用 futex 唤醒一个。 这种“没人抢走快路、有人抢才进内核”的设计,让锁在常见情况下几乎没有开销。
操作系统
多个线程同时改同一份数据会出错,锁保证同一时刻只有一个线程在改。
以 Linux 上两个线程同时给计数器加 1、用 pthread_mutex 保护为例。
步骤 6 / 9
抢不到锁时,线程通过 futex 系统调用请内核让自己睡眠,锁释放后再被唤醒。
一直空转重试(自旋)浪费 CPU,所以 Linux 的 pthread_mutex 抢不到时会调用 futex,让内核把线程挂起。 线程 1 解锁时,如果发现有人在等,就再调用 futex 唤醒一个。 这种“没人抢走快路、有人抢才进内核”的设计,让锁在常见情况下几乎没有开销。
| 当前状态 | 发生了什么 |
|---|---|
| 两个线程同时运行 | 两个线程读到同一个旧值,更新丢失 |
| 交错执行 | 执行顺序不可预测 |
| 动手实验 | 两个读都在写之前,丢一次更新 |
| 线程 1 持有锁 | 线程 1 独占临界区 |
| 线程 1 持有锁 | 线程 2 拿锁失败 |
| 线程 2 睡眠 → 被唤醒 | 线程 2 拿到锁,两次加 1 都生效 |