C语言中fork()、信号与父子进程的技术疑问
我来帮你拆解清楚这些疑惑,一步步捋明白:
一、父子进程的核心定义
当一个进程调用fork()系统调用时,操作系统会生成一个全新的进程——这个新进程就是子进程,而发起fork()的那个原始进程就是父进程。
- 子进程是父进程的「几乎完美副本」:它会复制父进程的代码、内存里的变量、打开的文件、信号处理规则等所有状态,但两者拥有完全独立的内存空间——子进程里的变量修改不会影响父进程,反之亦然。
- 父子进程是并行执行的,操作系统的调度器会决定哪个进程先拿到CPU时间片,所以它们的执行顺序默认是不确定的(除非用
wait()这类同步函数干预)。
二、signal(SIGUSR1, Paris);到底做了什么
signal()是用来给进程「注册信号处理规则」的函数:
- 第一个参数
SIGUSR1是一个用户自定义信号——这类信号是专门留给程序员在程序内部传递自定义事件的,系统不会主动发送它,得我们手动触发。 - 第二个参数
Paris是一个函数指针,意思是:当当前进程收到SIGUSR1信号时,就暂停当前正在跑的代码,转而去执行Paris函数,执行完再回到之前的代码继续跑。
三、kill(getpid(), SIGUSR1);的作用是什么
kill()函数的本职工作是给指定进程发送信号,参数含义是:
- 第一个参数是目标进程的PID(进程ID),
getpid()会返回当前进程自己的PID。 - 第二个参数是要发送的信号,这里是
SIGUSR1。
所以整句话的意思就是:给当前进程自己发送SIGUSR1信号,这样就会触发之前用signal()注册好的Paris函数执行,输出Paris。
四、关于输出顺序的疑问
你预期输出London StayHome Paris,这个结果是有可能出现的,但不是绝对的——因为父子进程并行执行,调度器可能先让子进程跑(输出StayHome),也可能先让父进程触发信号输出Paris。
如果想强制这个顺序,让父进程先等子进程跑完再执行信号逻辑,可以在父进程的kill()之前加一句wait(NULL),这样父进程会暂停,直到子进程退出,就能保证StayHome一定在Paris前面输出。
举个补全后的完整代码示例,方便你理解:
#include <signal.h> #include <stdio.h> #include <unistd.h> #include <sys/wait.h> void Paris() { printf("Paris "); } void StayHome() { printf("StayHome "); } int main() { printf("London "); // 注册SIGUSR1的处理函数 signal(SIGUSR1, Paris); // 创建子进程 pid_t pid = fork(); if (pid == 0) { // 子进程分支:输出StayHome后退出 StayHome(); return 0; } else if (pid > 0) { // 父进程分支:先等子进程跑完,再给自己发信号 wait(NULL); kill(getpid(), SIGUSR1); return 0; } else { // fork失败的情况 perror("fork failed"); return 1; } }
这段代码运行后会稳定输出London StayHome Paris。
内容的提问来源于stack exchange,提问作者Ray Sousa
相关产品推荐
相关产品推荐

