信号的基本概念
关于信号的详细说明可见 5.2 进程间有哪些通信方式? | 小林coding (xiaolincoding.com) 的“信号”部分,这里不再赘述。
关于信号的问题——信号是如何在应用进程和内核之间交互的?
上面给出的链接中有个“总结”部分,其中关于信号的介绍见下图:
上图中的划线处可引出一个问题——信号是如何在应用进程和内核之间交互的?详细过程可用下面的一张信号执行流程图说明:
针对信号执行流程图的一些疑问
17号信号是SIGCHLD信号,那SIGCHLD信号是什么
(解答来自ChatGPT)
SIGCHLD
是一个在 Unix 和类 Unix 操作系统中用于通知父进程子进程状态变化的信号。当子进程终止时,内核会向其父进程发送 SIGCHLD
信号。这个信号的主要作用是通知父进程子进程的终止状态,以便父进程可以采取适当的处理。
主要情况包括:
- 子进程终止: 当一个子进程终止时,内核向其父进程发送
SIGCHLD
信号。 - 子进程停止: 如果子进程停止或恢复执行,也会发送
SIGCHLD
信号,通知父进程子进程的状态发生了变化。 - 父进程对子进程状态的处理: 父进程通常通过调用
wait
或waitpid
系统调用来获取子进程的退出状态,以防止出现僵尸进程(zombie process)。
SIGCHLD
信号的处理通常包括以下几个步骤:
- 等待子进程退出: 父进程调用
wait
或waitpid
等待子进程退出。这样父进程就能够获取子进程的退出状态,避免子进程成为僵尸进程。 - 处理子进程退出状态: 父进程通过检查子进程的退出状态,了解子进程是正常退出还是异常退出,以及退出时的返回值等信息。
示例代码(C语言):
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void sigchld_handler(int signo) {
pid_t pid;
int status;
// 等待子进程退出
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (WIFEXITED(status)) {
printf("Child process %d exited with status %d\n", pid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Child process %d terminated by signal %d\n", pid, WTERMSIG(status));
}
}
}
int main() {
signal(SIGCHLD, sigchld_handler);
// 创建子进程
pid_t pid = fork();
if (pid == 0) {
// 子进程
printf("Child process\n");
sleep(2);
exit(42);
} else if (pid > 0) {
// 父进程
printf("Parent process\n");
// 父进程可以继续执行其他操作
// 等待 SIGCHLD 信号处理子进程退出
while (1) {
sleep(1);
}
} else {
perror("fork");
return 1;
}
return 0;
}
在上述示例中,父进程通过 waitpid
函数等待子进程退出,并通过 WIFEXITED
和 WIFSIGNALED
宏检查子进程的退出状态。当子进程终止时,会触发 SIGCHLD
信号,执行 sigchld_handler
处理函数。
pid_t pid = fork();的含义是什么
pid_t pid = fork();
是在 C 语言中创建一个新进程的方式之一,使用了 fork
系统调用。这行代码的含义是创建一个子进程,并且在父子进程中分别返回不同的值。
具体来说:
fork
是一个系统调用,调用一次,返回两次。它创建了一个新的进程,新进程是调用进程的副本,称为子进程。在父进程和子进程中,fork
的返回值是不同的。- 在父进程中,
fork
返回新创建的子进程的进程ID(PID),即子进程的PID。 - 在子进程中,
fork
返回0
,表示当前进程是子进程。
示例代码:
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid == -1) {
// 创建子进程失败
perror("fork");
return 1;
} else if (pid == 0) {
// 子进程代码
printf("This is the child process. PID: %d\n", getpid());
} else {
// 父进程代码
printf("This is the parent process. Child PID: %d\n", pid);
}
// 这里的代码会在父子进程中都执行
return 0;
}
在这个例子中,fork
调用后,父进程和子进程都会执行 if
、else if
语句块后面的代码,但由于 fork
的返回值不同,它们会在不同的分支中执行。在父进程中,pid
是子进程的PID;在子进程中,pid
是0。
exit(42);的含义是什么
exit(42)
是一个在 C 语言中用于终止程序执行的语句。具体来说,exit
函数用于正常地终止程序,并返回一个退出状态码(exit status)。在这里,42
是退出状态码的值。
在 Unix/Linux 等操作系统中,程序的退出状态码是一个整数,通常用于传递程序的退出状态给调用它的进程。约定上,一个程序返回 0
表示正常退出,而其他非零值则表示某种错误或异常情况。
WIFEXITED和WIFSIGNALED的含义是什么
在C语言的进程控制中,WIFEXITED
和 WIFSIGNALED
是两个宏,用于判断子进程的终止状态。WIFEXITED(status)
用于判断子进程是否正常终止。WIFSIGNALED(status)
用于判断子进程是否因为信号而终止。因此,用exit(42)正常退出时,WIFEXITED(status)
返回true。