跨进程线程通信问题: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
相关产品推荐
相关产品推荐

