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

64位Ubuntu系统下使用-m32编译选项时sem_wait调用阻塞的解决方法咨询

解决32位编译下sem_wait阻塞的问题

这个问题的核心原因大概率是信号量初始化不规范或者32/64位环境下sem_t结构的内存布局差异导致的,我来给你拆解具体原因和可行的解决方案:

问题根源分析

  1. 缺失信号量初始化步骤:你提供的代码片段里没有展示共享内存的创建和sem_t的初始化逻辑。如果在fork()前没有正确初始化信号量(尤其是进程间共享的信号量),32位环境下sem_wait会因为信号量处于无效状态而无限阻塞。
  2. 32/64位sem_t结构差异:Linux系统中,32位和64位程序的sem_t结构体大小、成员偏移可能不同。如果共享内存是由64位程序创建的,32位程序直接访问会导致信号量读写错误,进而触发阻塞。

解决方案一:规范初始化无名信号量(基于共享内存)

如果坚持用共享内存存放无名信号量,必须在fork()前完成共享内存的创建、映射和信号量的初始化,确保父子进程都能访问到正确的信号量结构。修改后的完整代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>

#define HSDPA_MT_PRINT_LOCK_SEM_IDX 0
#define HSDPA_MT_ZERO 0

// 定义包含信号量的共享内存结构
typedef struct {
    sem_t sem;
} SharedSemData;

SharedSemData *SemOpenShmAddr;

void func1() {
    sleep(2);
    sem_wait(&SemOpenShmAddr->sem);
    // 临界区操作
    printf("func1: 进入临界区\n");
    sem_post(&SemOpenShmAddr->sem);
    printf(" exit func1\n");
}

void func2() {
    sleep(2);
    sem_wait(&SemOpenShmAddr->sem);
    // 临界区操作
    printf("func2: 进入临界区\n");
    sem_post(&SemOpenShmAddr->sem);
    printf(" exit func2\n");
}

int main (int argc, char **argv) {
    pid_t pid;
    int shm_fd;
    const char *shm_name = "/mt_print_lock_shm";

    // 1. 创建/打开共享内存
    shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
    if (shm_fd == -1) {
        perror("shm_open 失败");
        exit(EXIT_FAILURE);
    }

    // 2. 设置共享内存大小为结构体大小
    if (ftruncate(shm_fd, sizeof(SharedSemData)) == -1) {
        perror("ftruncate 失败");
        exit(EXIT_FAILURE);
    }

    // 3. 映射共享内存到进程地址空间
    SemOpenShmAddr = mmap(NULL, sizeof(SharedSemData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (SemOpenShmAddr == MAP_FAILED) {
        perror("mmap 失败");
        exit(EXIT_FAILURE);
    }

    // 4. 初始化信号量:第二个参数为1表示允许进程间共享,第三个参数为1表示初始值为1(互斥锁)
    if (sem_init(&SemOpenShmAddr->sem, 1, 1) == -1) {
        perror("sem_init 失败");
        exit(EXIT_FAILURE);
    }

    pid = fork();
    if (HSDPA_MT_ZERO == pid) {
        // 子进程
        func1();
        munmap(SemOpenShmAddr, sizeof(SharedSemData));
        close(shm_fd);
    } else {
        // 父进程
        func2();
        wait(NULL); // 等待子进程结束
        // 清理资源
        sem_destroy(&SemOpenShmAddr->sem);
        munmap(SemOpenShmAddr, sizeof(SharedSemData));
        close(shm_fd);
        shm_unlink(shm_name);
    }

    return 0;
}

32位编译注意事项

  • 先安装32位开发依赖:
    sudo apt-get install libc6-dev-i386 lib32stdc++6
    
  • 编译时需要链接实时库-lrt(因为shm_open属于实时扩展):
    gcc -g -m32 sem_sample1.c -o sem_sample1 -lpthread -lrt
    

解决方案二:使用有名信号量(更简单的跨位兼容方案)

有名信号量由操作系统内核管理,不需要手动处理共享内存,天然避免32/64位结构差异问题。修改后的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/wait.h>

#define HSDPA_MT_PRINT_LOCK_SEM_IDX 0
#define HSDPA_MT_ZERO 0

sem_t *print_sem;

void func1() {
    sleep(2);
    sem_wait(print_sem);
    // 临界区操作
    printf("func1: 进入临界区\n");
    sem_post(print_sem);
    printf(" exit func1\n");
}

void func2() {
    sleep(2);
    sem_wait(print_sem);
    // 临界区操作
    printf("func2: 进入临界区\n");
    sem_post(print_sem);
    printf(" exit func2\n");
}

int main (int argc, char **argv) {
    pid_t pid;
    const char *sem_name = "/mt_print_lock_sem";

    // 创建/打开有名信号量:初始值设为1(互斥锁)
    print_sem = sem_open(sem_name, O_CREAT | O_RDWR, 0666, 1);
    if (print_sem == SEM_FAILED) {
        perror("sem_open 失败");
        exit(EXIT_FAILURE);
    }

    pid = fork();
    if (HSDPA_MT_ZERO == pid) {
        // 子进程
        func1();
        sem_close(print_sem);
    } else {
        // 父进程
        func2();
        wait(NULL); // 等待子进程结束
        sem_close(print_sem);
        sem_unlink(sem_name); // 删除有名信号量
    }

    return 0;
}

32位编译命令

同样需要链接-lrt和-lpthread:

gcc -g -m32 sem_sample1.c -o sem_sample1 -lpthread -lrt

关键总结

  • 信号量必须在fork()前完成初始化,确保父子进程共享同一个有效的信号量实例;
  • 无名信号量用于进程间同步时,必须放在共享内存中,且sem_init的第二个参数要设为1;
  • 32位编译必须安装对应的32位依赖库,否则会出现链接错误;
  • 有名信号量是更省心的跨位兼容方案,不需要手动管理共享内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 21:27:46