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

信号量(Semaphore)未正确锁定:线程执行结果不符预期求助

线程临界区保护后输出异常的问题解决

问题场景

创建了两个线程:

  • thread1执行write_ticket函数:通过信号量锁定临界区,将ticketnumber设为5000,休眠1秒后打印该值
  • thread2执行ticketIncrease函数:同样用信号量锁定临界区,将ticketnumber自增1后打印

预期输出是先打印5000,再打印5001,但实际两次都打印5001;把sleep替换成打印语句后,问题消失。

问题原因

  1. 线程函数签名不符合pthread要求(核心问题)
    pthread库规定线程入口函数必须是void* (*)(void*)类型,但你的两个线程函数都是void返回类型。这种类型不匹配会触发未定义行为——比如栈帧被破坏、信号量的sem_post操作未正确执行,直接导致临界区的互斥保护失效,线程间的操作顺序彻底混乱。

  2. 共享变量未加volatile修饰(潜在优化干扰)
    全局变量ticketnumber被多线程读写,但没加volatile修饰。编译器可能会把这个变量的值缓存到寄存器里,导致某个线程无法及时看到其他线程对变量的修改,进一步加剧结果的不确定性。

  3. 线程调度顺序不确定(非直接原因)
    pthread_create只是创建线程,操作系统的线程调度顺序是随机的,先创建的线程未必先执行。但正常情况下信号量会保证临界区互斥,只是前面的错误让信号量失去了作用。

修正后的代码

#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

// 加volatile防止编译器优化,保证线程间变量可见性
volatile int ticketnumber = 0;
sem_t sem;

// 修正线程函数签名,符合pthread要求的void*返回类型
void* write_ticket(void* arg){
    sem_wait(&sem);
    ticketnumber = 5000;
    sleep(1);
    printf("%d\n", ticketnumber);
    sem_post(&sem);
    return NULL; // 必须返回void*类型的值
}

// 同样修正线程函数签名
void* ticketIncrease(void* arg){
    sem_wait(&sem);
    ticketnumber += 1;
    printf("%d\n", ticketnumber);
    sem_post(&sem);
    return NULL;
}

int main(){
    // 检查信号量初始化是否成功,增强健壮性
    if (sem_init(&sem, 0, 1) != 0) {
        perror("sem_init failed");
        exit(EXIT_FAILURE);
    }
    pthread_t thread1;
    pthread_t thread2;
    // 签名匹配后无需强制类型转换
    pthread_create(&thread1, NULL, write_ticket, NULL);
    pthread_create(&thread2, NULL, ticketIncrease, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    // 程序结束前销毁信号量
    sem_destroy(&sem);
    return 0;
}

修正说明

  • 调整线程函数的返回类型为void*,并返回NULL,彻底解决类型不匹配导致的未定义行为,让信号量的互斥保护正常工作。
  • 给ticketnumber加上volatile修饰,确保每次读写都直接操作内存,避免编译器缓存导致的变量可见性问题。
  • 增加了信号量初始化的错误检查和销毁操作,让代码更规范健壮。

为什么替换sleep为打印就正常?

当把sleep换成打印语句时,线程函数的执行时间极短,可能在栈帧被破坏前就完成了信号量释放和打印操作,侥幸得到了预期结果,但这只是巧合,不是正确的解决方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 02:57:33