wait()触发Interrupted system call异常:多进程共享内存场景排查请求
问题排查:wait()返回"Interrupted system call"偶现问题
问题描述
原本预期wait()函数会等待所有子进程执行完毕,但实际运行中该函数偶现返回-1,提示"Interrupted system call"。调试模式下运行无异常,曾怀疑问题与共享内存相关。
代码示例
#include <stdio.h> #include <stdlib.h> #include <sys/shm.h> #include <unistd.h> #include <errno.h> #define PROCESSES 3 struct shdata { int x; }; void childf(int shared_memory, int index) { // connect shared memory struct shdata* shm = (struct shdata*)shmat(shared_memory, NULL, 0); if(shm == (void*)-1) { perror("shmat"); exit(0); } // initialize x as 0 if(index == 0) { shm->x = 0; } // increment x shm->x++; //show x printf("Proces %d: x = %d\n", index, shm->x); // disconnect shared memory if(shmdt(shm) == -1) { perror("shmdt"); exit(0); } // end child process exit(0); } int main(int argc, const char * argv[]) { // create shared memory int shared_memory = shmget(IPC_PRIVATE, 4096, 0600 | IPC_CREAT | IPC_EXCL); if(shared_memory == -1) { perror("shmget"); return 1; } // create child processes for (int i = 0; i < PROCESSES; i++) { int pid = fork(); if(pid == -1) { perror("fork"); return 5; } if(pid == 0) { childf(shared_memory, i); } } // wait for child processes for(int i = 0; i < PROCESSES; i++) { int wait_res = wait(NULL); if(wait_res < 0) { perror("wait"); return 6; } } // delete shared memory int delete_memory = shmctl(shared_memory, IPC_RMID, NULL); if(delete_memory == -1) { perror("shmctl"); return 4; } return 0; }
实际输出
Proces 0: x = 1 Proces 1: x = 2 Proces 2: x = 3 wait: Interrupted system call Program ended with exit code: 6
预期输出
Proces 0: x = 1 Proces 1: x = 2 Proces 2: x = 3 Program ended with exit code: 0
问题原因与解决方案
原因分析
这个问题和共享内存无关,核心原因是**wait()被信号中断**。当进程处于wait()这类阻塞系统调用时,如果收到一个未被忽略的信号,系统调用会被强制打断,返回-1,同时errno被设置为EINTR(对应提示的"Interrupted system call")。
调试模式下无异常,是因为调试器会接管进程的信号处理,或者运行节奏变慢,未触发导致中断的信号,所以问题不会显现。
解决方案
标准处理方式是捕获EINTR错误,重新调用wait()——因为系统调用被中断不代表没有子进程需要等待,只是被信号打断了,重试即可。
修改main()中等待子进程的代码段:
// wait for child processes int wait_count = 0; while (wait_count < PROCESSES) { int wait_res = wait(NULL); if (wait_res < 0) { if (errno == EINTR) { // 被信号中断,重试wait调用 continue; } perror("wait"); return 6; } wait_count++; }
也可以使用waitpid(-1, NULL, 0)替代wait(),处理逻辑一致,同样需要捕获EINTR重试。
内容的提问来源于stack exchange,提问作者Єгорій
相关产品推荐
相关产品推荐

