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

跨进程线程通信问题:P5线程T5.3需先于P7线程T7.2结束

嘿,这个问题我太懂了!你之前用sem_wait和sem_post没搞定,核心原因应该是用了进程内的无名信号量——这种信号量只存在于单个进程的地址空间里,另一个进程根本看不到它。要实现不同进程间线程的同步,必须用跨进程可见的信号量,主要有两种靠谱的方案,我给你一步步讲清楚:

方案一:使用POSIX命名信号量

命名信号量是系统级别的,所有进程都可以通过同一个名字来访问它,非常适合跨进程同步。

实现步骤:

  • 在两个进程中,用sem_open()打开同一个命名信号量(如果不存在就创建),初始值设为0(这样T7.2一开始会阻塞,直到T5.3发信号)。
  • 在进程P5的线程T5.3中,当它完成所有任务后,调用sem_post()来释放信号量。
  • 在进程P7的线程T7.2中,在执行核心任务之前,调用sem_wait()来等待信号量——只有当T5.3调用了sem_post()后,T7.2才会继续执行。
  • 程序结束后,记得用sem_close()关闭信号量,用sem_unlink()删除系统中的信号量文件。

代码示例:

进程P5中的T5.3线程代码:

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

void* thread_T5_3(void* arg) {
    // 执行T5.3的核心任务
    printf("T5.3: 正在执行任务...\n");
    // 模拟任务耗时
    sleep(2);
    printf("T5.3: 任务完成,释放信号量\n");

    // 打开命名信号量(名字要以"/"开头,是POSIX的要求)
    sem_t* sync_sem = sem_open("/thread_sync_sem", O_CREAT, 0666, 0);
    if (sync_sem == SEM_FAILED) {
        perror("sem_open failed");
        pthread_exit(NULL);
    }

    // 发送信号,通知T7.2可以开始
    sem_post(sync_sem);

    // 关闭信号量
    sem_close(sync_sem);
    pthread_exit(NULL);
}

进程P7中的T7.2线程代码:

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

void* thread_T7_2(void* arg) {
    // 打开同一个命名信号量
    sem_t* sync_sem = sem_open("/thread_sync_sem", O_CREAT, 0666, 0);
    if (sync_sem == SEM_FAILED) {
        perror("sem_open failed");
        pthread_exit(NULL);
    }

    printf("T7.2: 等待T5.3完成任务...\n");
    // 等待信号量,直到T5.3调用sem_post
    sem_wait(sync_sem);
    printf("T7.2: 收到信号,开始执行任务\n");

    // 执行T7.2的核心任务
    sleep(1);
    printf("T7.2: 任务完成\n");

    // 关闭信号量
    sem_close(sync_sem);
    // 注意:只有最后一个使用信号量的进程需要调用sem_unlink,避免系统残留
    sem_unlink("/thread_sync_sem");
    pthread_exit(NULL);
}
方案二:使用共享内存+无名信号量

如果不想用命名信号量,也可以把无名信号量放到共享内存中,让两个进程映射同一块共享内存,从而共享这个信号量。

实现步骤:

  • 创建一块共享内存(用shmget()),然后分别在P5和P7中把它映射到自己的地址空间(shmat())。
  • 在共享内存中初始化一个无名信号量(用sem_init(),注意要设置pshared参数为1,表示可以跨进程共享)。
  • T5.3完成任务后调用sem_post(),T7.2执行前调用sem_wait()。
  • 程序结束后,解除映射(shmdt()),删除共享内存(shmctl())。

代码示例(核心部分):

共享内存结构体定义(两个进程都要包含):

#include <semaphore.h>

typedef struct {
    sem_t sync_sem;
} SharedData;

进程P5中的T5.3线程:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void* thread_T5_3(void* arg) {
    // 创建或获取共享内存
    key_t key = ftok("/tmp", 'A'); // 用一个固定的文件和字符生成key
    int shmid = shmget(key, sizeof(SharedData), IPC_CREAT | 0666);
    if (shmid == -1) {
        perror("shmget failed");
        pthread_exit(NULL);
    }

    // 映射共享内存到进程地址空间
    SharedData* shared_data = (SharedData*)shmat(shmid, NULL, 0);
    if (shared_data == (void*)-1) {
        perror("shmat failed");
        pthread_exit(NULL);
    }

    // 初始化信号量(只需要在一个进程中初始化一次)
    sem_init(&shared_data->sync_sem, 1, 0); // pshared=1表示跨进程共享,初始值0

    // 执行T5.3任务
    printf("T5.3: 执行任务中...\n");
    sleep(2);
    printf("T5.3: 任务完成,发送信号\n");

    // 释放信号量
    sem_post(&shared_data->sync_sem);

    // 解除映射
    shmdt(shared_data);
    pthread_exit(NULL);
}

进程P7中的T7.2线程:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void* thread_T7_2(void* arg) {
    // 获取同一个共享内存
    key_t key = ftok("/tmp", 'A');
    int shmid = shmget(key, sizeof(SharedData), 0666);
    if (shmid == -1) {
        perror("shmget failed");
        pthread_exit(NULL);
    }

    // 映射共享内存
    SharedData* shared_data = (SharedData*)shmat(shmid, NULL, 0);
    if (shared_data == (void*)-1) {
        perror("shmat failed");
        pthread_exit(NULL);
    }

    printf("T7.2: 等待T5.3完成...\n");
    // 等待信号量
    sem_wait(&shared_data->sync_sem);
    printf("T7.2: 开始执行任务\n");

    // 执行T7.2任务
    sleep(1);
    printf("T7.2: 任务完成\n");

    // 销毁信号量,删除共享内存
    sem_destroy(&shared_data->sync_sem);
    shmdt(shared_data);
    shmctl(shmid, IPC_RMID, NULL);

    pthread_exit(NULL);
}

关键注意点:

  • 不管用哪种方案,信号量的初始值一定要设为0,这样T7.2会先阻塞,直到T5.3触发sem_post。
  • 命名信号量的名字必须以/开头,这是POSIX标准的要求,避免和系统其他资源冲突。
  • 使用共享内存时,ftok()的参数要保证两个进程用同一个文件和字符,否则生成的key不一样,会获取不到同一块共享内存。
  • 记得做好错误处理,避免因为系统调用失败导致同步失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:26:37