You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pthreads如何阻止编译器跨pthread_mutex_lock调用将变量缓存到寄存器

问题背景

假设存在两个线程访问受锁保护的全局变量var,示例代码如下:

#include <pthread.h>
#include <stdio.h>

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static int var;

void *thread1_func(void *ptr) {
    pthread_mutex_lock(&lock);
    var = var + 1;
    printf("Thread 1: %d\n", var);
    pthread_mutex_unlock(&lock);
}

int main() {
    pthread_t thread1;

    var = 0;
    pthread_create(&thread1, NULL, thread1_func, NULL);

    pthread_mutex_lock(&lock);
    printf("Thread 0: %d\n", var);
    pthread_mutex_unlock(&lock);

    pthread_join(thread1, NULL);

    return 0;
}

假设指令按如下顺序交错执行:

Thread 0:                                                  Thread 1:
1. var = 0;
2. pthread_create(&thread1, NULL, thread1_func, NULL);
                                                           3. pthread_mutex_lock(&lock);
                                                           4. var = var + 1;
                                                           5. printf("Thread 1: %d\n", var);
                                                           6. pthread_mutex_unlock(&lock);
7. pthread_mutex_lock(&lock);
8. printf("Thread 0: %d\n", var); // 预期打印1!
9. pthread_mutex_unlock(&lock);

C标准本身没有明确定义并发模型,所以理论上符合标准的C编译器允许跨pthread_mutex_lock()调用将var的值缓存到寄存器中,导致步骤8打印0,但实际pthreads API的实现都会采取措施避免该问题。

问题

请问pthreads的实现是如何阻止编译器跨pthread_mutex_lock()调用将var的值缓存到寄存器的?请说明pthreads源码中向编译器传递相关信息的具体注解,可任选一种pthreads实现作答,例如面向aarch64架构编译的glibc。本题假设pthread_mutex_lock()定义在同一文件中,且编译器可证明其不会访问var。


解答

我们以glibc的aarch64架构实现为例说明:

  • glibc的pthread_mutex_lock、pthread_mutex_unlock等同步原语实现中,都会内嵌编译器内存屏障注解,最常见的形式是asm volatile ("" ::: "memory")。
  • 该注解的作用是明确告知编译器:这段内嵌汇编代码可能读取或修改所有可见内存地址,因此编译器不能将这段代码前后的内存访问指令重排越过该屏障,也不能把屏障前缓存在寄存器中的变量值直接拿到屏障后使用,必须在屏障后重新从内存加载变量的最新值。
  • 哪怕编译器可以证明pthread_mutex_lock本身的代码没有显式访问var,这个内存屏障注解也会强制编译器丢弃之前缓存的var寄存器值,在调用pthread_mutex_lock之后重新从内存读取var的最新值,因此步骤8必然能读到线程1修改后的值1。
  • 除了编译器层面的内存屏障,同步原语实现中还会加入对应架构的CPU内存屏障指令(aarch64上为dmb/dsb指令),用来阻止CPU层面的指令重排,保证多核心的缓存一致性,避免其他核心的修改对当前核心不可见。

内容的提问来源于stack exchange,提问作者Jorge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 06:24:03