专业做民宿的网站,永康网站优化公司,营销推广有哪些形式,创新logo设计目录 信号的概念
生活中的信号
Linux中的信号
kill命令
kill 命令的使用
常见的信号
命令行代码示例
注意事项
信号的处理方式
产生信号
信号的捕捉
信号捕捉示意图
内核如何实现信号捕捉
信号的捕捉与处理
小结
阻塞信号
信号在内核中的表示图
信号集操作函数…目录 信号的概念
生活中的信号
Linux中的信号
kill命令
kill 命令的使用
常见的信号
命令行代码示例
注意事项
信号的处理方式
产生信号
信号的捕捉
信号捕捉示意图
内核如何实现信号捕捉
信号的捕捉与处理
小结
阻塞信号
信号在内核中的表示图
信号集操作函数
可重入函数
可重入函数示意图
可重入函数概念
可重入函数的使用
volatile关键字
SIGHLD信号
SIGHLD信号介绍
SIGCHLD信号的概念
SIGCHLD信号的作用
SIGCHLD信号使用示例
示例代码实现
示例代码解释
示例代码总结 信号的概念
在Linux中信号是一种软件中断用于通知进程发生了某个事件。这些事件可能是用户请求如按下CtrlC也可能是内核通知如进程访问了无效的内存地址。信号提供了一种机制使得进程能够响应这些事件并采取适当的行动。
信号的递达与未决
一、信号的递达
信号的递达是指进程实际执行信号的处理动作。当信号被发送给一个进程后操作系统会进行相应的处理确保信号能够准确地传递给目标进程。一旦信号被递达给进程进程就会根据信号的类型和设定的处理方式执行相应的动作。
在信号的递达过程中进程可以自定义信号的处理函数用于执行特定的逻辑。当信号递达时进程会调用相应的处理函数并执行其中的代码。这样进程可以根据不同的信号进行不同的处理以满足不同的需求。
二、信号的未决
信号的未决状态是指信号从产生到递达之间的状态。当一个信号被发送给一个进程后该信号首先会处于未决状态。这意味着信号已经产生但还没有被进程实际处理。
在信号的未决状态中操作系统会维护一个信号未决表用于记录当前进程尚未处理的信号。这个表记录了哪些信号已经产生但尚未递达给进程。进程可以通过检查信号未决表来了解当前有哪些信号等待处理。
进程的信号未决状态可以被阻塞或解除阻塞。当进程选择阻塞某个信号时该信号将保持在未决状态不会被递达给进程。只有当进程解除对该信号的阻塞时信号才会从未决状态转变为递达状态进而执行相应的处理动作。
通过信号的递达和未决机制操作系统能够灵活地管理进程对信号的处理。进程可以根据需要自定义信号的处理方式并在合适的时机执行相应的处理动作。这种机制为进程间的通信和异常处理提供了强大的支持。
生活中的信号 闹钟信号假设你设定了一个闹钟在早上7点响铃。这个闹钟响铃就是一个信号通知你该起床了。在Linux中这可以类比为一个进程设定了一个定时器如使用setitimer系统调用当定时器到期时内核会向该进程发送一个信号如SIGALRM通知它定时器已经到期。 电话铃声当你正在做其他事情时电话铃声响起这是一个信号告诉你有人正在呼叫你。你可以选择接听电话、挂断电话或忽略它。在Linux中当一个进程接收到一个信号时它可以选择忽略该信号、执行默认操作或自定义一个信号处理函数来处理该信号。 交通信号灯交通信号灯是道路上的重要信号告诉驾驶员何时可以前进、何时需要停止或等待。如果驾驶员违反信号灯指示可能会引发交通事故。类似地在Linux中如果进程不正确地处理信号如忽略重要的信号可能会导致不可预期的行为或程序崩溃。 敲门声当你正在房间里工作时突然听到敲门声这是一个信号告诉你有人想要和你交流。你可以继续工作不理会敲门声也可以停下来去开门。在Linux中进程可以选择忽略某些信号如SIGCHLD当子进程状态改变时发送也可以对它们进行特殊处理。
Linux中的信号
Linux中的信号是一种进程间通信Inter-Process Communication, IPC机制用于向其他进程发送通知或指示通常是为了通知特定事件的发生如程序终止、用户按下特定按键等。信号提供了一种异步的、非阻塞的通信方式因此在某些情况下非常有用。
信号全称为软中断信号也有人称作软中断。信号机制是进程之间相互传递消息的一种方法。进程之间可以互相通过系统调用kill发送软中断信号通知进程发生了某个事件。内核也可以因为内部事件而给进程发送信号通知进程发生了某个事件。例如当中断用户键入中断键CTRLC时会通过信号机制停止一个程序。
Linux系统定义了64种信号这些信号可以分为两类可靠信号与不可靠信号。前32种信号为不可靠信号也称为非实时信号它们不支持排队信号可能会丢失。比如发送多次相同的信号进程只能收到一次。而后32种信号为可靠信号也称为实时信号它们支持排队信号不会丢失发多少次就可以收到多少次。
每种信号都有其特定的用途和处理方式。例如SIGTERM信号用于请求终止进程它可以被捕获或忽略SIGQUIT信号请求进程退出并产生core文件同样可以被捕获或忽略而SIGSTOP信号会暂停进程的执行并且不能被捕获或忽略。
在Linux中进程可以选择忽略某些信号也可以自定义信号处理函数来处理特定信号。当进程接收到一个信号时它会根据信号的类型和当前的状态来决定如何响应。如果进程没有为某个信号指定处理函数那么它会执行该信号的默认操作。
总的来说Linux中的信号机制为进程间的通信和同步提供了强大的支持使得进程能够灵活地响应各种事件和条件。通过合理地使用和处理信号我们可以编写出更加健壮和高效的程序。
kill命令
kill通常kill 命令用于终止进程但实际上它可以发送任何有效的信号给进程。默认情况下kill命令发送SIGTERM信号该信号会请求进程优雅地终止。如果进程没有响应SIGTERM信号可以使用kill -9命令发送SIGKILL 信号强制终止进程。
kill 命令的使用
kill 命令的基本语法如下
kill [选项] 进程ID [进程ID ...]或者
kill -s 信号 进程ID其中进程ID 是你想要发送信号的进程的进程ID信号 是你想要发送的信号名或信号编号。
常见的信号 SIGTERM默认信号编号 15请求进程终止。进程在接收到此信号后可以执行清理操作并退出。 SIGKILL编号 9强制终止进程。进程在接收到此信号后不能捕获或忽略它会立即停止执行。 SIGINT编号 2通常由 CtrlC 产生请求进程中断。 SIGHUP编号 1当控制终端挂起时通知进程。
命令行代码示例 发送 SIGTERM 信号终止进程
如果你知道进程的ID比如 1234你可以使用以下命令来发送 SIGTERM 信号
kill 1234如果进程没有响应你可以使用 kill -l 来查看所有可用的信号列表并决定发送哪种信号。 发送 SIGKILL 信号强制终止进程
如果 SIGTERM 没有效果你可以发送 SIGKILL 信号来强制终止进程
kill -9 1234这条命令会强制终止进程ID为 1234 的进程。 发送特定信号
如果你想发送一个特定的信号比如 SIGHUP你可以使用 -s 选项
kill -s SIGHUP 1234或者你也可以使用信号的编号
kill -1 1234这条命令会向进程ID为 1234 的进程发送 SIGHUP 信号。 发送信号给多个进程
你可以一次向多个进程发送信号
kill 1234 5678这条命令会向进程ID为 1234 和 5678 的进程发送 SIGTERM 信号。 5. 查看信号列表 你可以查看信号列表
kill -l注意事项 在使用 kill -9 之前请确保你已经尝试了 SIGTERM 信号因为 SIGKILL 会立即停止进程不给进程任何清理的机会。 不是所有的进程都可以被 kill 命令终止。有些系统进程或守护进程可能设计为忽略某些信号。 错误的 kill 命令可能会导致系统不稳定或数据丢失所以请确保你知道正在终止什么进程以及这个操作可能带来的后果。
kill 命令是一个非常强大的工具但也需要谨慎使用。在发送信号之前最好先了解进程的用途和重要性以避免不必要的系统干扰或数据损失。
信号的处理方式
在Linux中常见的信号处理方法主要有以下几种 忽略信号当进程接收到某个信号时可以选择忽略它即不执行任何操作。这通常用于处理那些对进程来说不重要的信号。 执行默认处理动作对于每个信号系统都定义了一个默认的处理动作。当进程接收到信号且没有自定义处理函数时就会执行这个默认动作。例如对于SIGTERM信号默认的处理动作是终止进程。 自定义信号处理函数进程可以注册一个信号处理函数当接收到特定信号时内核会调用这个函数来处理信号。这种方式允许进程根据信号的类型和当前的状态来执行特定的操作如清理资源、记录日志等。通过自定义信号处理函数进程可以更加灵活地响应各种事件和条件。
需要注意的是并非所有的信号都可以被忽略或自定义处理。例如SIGKILL和SIGSTOP等信号是不能被忽略或捕获的它们会强制终止进程或暂停进程的执行。
产生信号
在Linux中信号的产生主要有以下几种方式 通过键盘产生 用户可以通过特定的按键组合来产生信号。例如按下CtrlC会产生SIGINT信号通常用于终止前台进程。这种信号产生方式实际上是操作系统捕获到键盘上的按键组合并将其解析成相应的信号然后发送给目标进程。 通过系统调用产生 Linux提供了多个系统调用来产生信号其中最常见的是kill和raise函数。 kill函数允许一个进程向另一个进程发送信号。通过指定目标进程的进程ID和要发送的信号可以实现对目标进程的控制如终止进程、暂停进程等。 raise函数则允许一个进程向自身发送信号常用于实现进程内部的信号处理逻辑。 由软件条件产生 当某些软件条件满足时操作系统会自动向进程发送信号。例如当进程访问了非法内存地址时会产生SIGSEGV信号当进程执行了除零操作时会产生SIGFPE信号。此外定时器到期、I/O操作完成等事件也会触发相应的信号。 由硬件异常产生 当硬件发生异常时如CPU异常、总线错误等操作系统会向相关进程发送信号。这些信号通常用于通知进程硬件层面的错误以便进程能够采取相应的处理措施。
信号的捕捉
信号捕捉示意图 内核如何实现信号捕捉
在Linux内核中信号捕捉的实现涉及多个组件和步骤。信号捕捉允许进程在接收到信号时执行自定义的处理逻辑而不是采用默认的信号处理行为。以下是信号捕捉在内核中的实现细节的详细介绍 信号注册与信号处理器设置 当进程通过signal()或sigaction()系统调用设置信号处理器时内核会记录该进程的信号处理器信息。 内核维护了一个数据结构如task_struct中的字段该结构包含指向每个信号对应的处理器函数的指针。 信号产生 信号可以由多种原因产生如用户按下CtrlC产生SIGINT信号或者内核检测到某种异常条件如段错误产生SIGSEGV信号。 当信号产生时内核会更新目标进程的信号状态将其标记为未决状态。 信号传递 内核定期检查进程的信号状态并尝试将未决信号传递给进程。 在信号传递之前内核会检查进程是否阻塞了该信号。如果信号被阻塞则保持未决状态否则进入信号处理流程。 信号处理 内核调用进程为该信号设置的处理器函数也称为信号处理程序。 信号处理程序可以在用户空间执行这意味着当处理程序被调用时内核会切换到用户模式并执行处理程序中的代码。 信号处理程序可以执行任何合法的用户空间代码包括改变程序的控制流、修改变量值或执行其他任务。 信号恢复 信号处理程序执行完毕后控制流返回到内核内核负责恢复进程的上下文并继续执行。 内核还负责清理信号处理过程中的任何临时状态确保系统的稳定性。 信号与阻塞 进程可以使用sigprocmask()等系统调用来修改其信号屏蔽字即阻塞的信号集。 当进程阻塞某个信号时该信号即使产生也不会被立即处理而是保持未决状态直到进程解除对该信号的阻塞。 实时信号与排队 Linux支持实时信号这些信号与普通信号的主要区别在于它们可以排队等待处理。 对于实时信号内核会为每个信号维护一个队列允许多个相同的实时信号被同时接收并排队等待处理。 安全性与可靠性 内核在信号处理过程中要确保系统的安全性和可靠性。 例如内核会检查信号处理程序的有效性防止恶意代码的执行。 内核还会处理信号处理过程中的异常情况如处理程序中的错误或异常退出。
信号的捕捉与处理
一、信号的捕捉
在Linux中信号的捕捉是指进程在接收到信号时不是按照信号的默认行为来处理而是执行自定义的信号处理函数。这样进程就可以根据信号的种类和当前的状态来决定如何响应信号。
二、使用sigaction设置信号处理函数
sigaction函数提供了更丰富的功能并且更加安全因此在实际应用中更为常用。下面将介绍如何使用sigaction函数来设置信号处理函数。
三、捕捉空指针异常SIGSEGV的示例
下面以捕捉空指针异常即SIGSEGV信号为例展示如何使用sigaction函数来设置信号处理函数。
3.1 定义信号处理函数
首先需要定义一个信号处理函数该函数将在接收到信号时被调用。在这个例子中我们定义了一个名为handle_segv的函数用于处理SIGSEGV信号。
#include stdio.h
#include stdlib.h
#include signal.h
#include unistd.h
#include string.h
#include execinfo.hvoid handle_segv(int sig, siginfo_t *info, void *context) {// 处理SIGSEGV信号的逻辑如打印调用栈信息
}3.2 设置信号处理函数
接下来在程序的主函数中使用sigaction函数来设置SIGSEGV信号的处理函数。
int main() {struct sigaction sa;memset(sa, 0, sizeof(sa));sa.sa_sigaction handle_segv;sa.sa_flags SA_SIGINFO;if (sigaction(SIGSEGV, sa, NULL) -1) {// 处理设置信号处理函数失败的情况}// 程序的正常逻辑可能会触发SIGSEGV信号return 0;
}在上述代码中sigaction函数用于设置SIGSEGV信号的处理函数为handle_segv。当程序因为解引用空指针而触发SIGSEGV信号时会调用handle_segv函数来处理该信号。
3.3 触发空指针异常并处理
在程序的正常逻辑中可以故意触发一个空指针异常来测试信号捕捉的处理逻辑。例如通过解引用一个空指针来触发SIGSEGV。
// 在程序的正常逻辑中触发空指针异常
int *ptr NULL;
*ptr 1; // 这将导致SIGSEGV信号当程序执行到这一行时会触发SIGSEGV信号并调用之前设置的handle_segv函数来处理该信号。在handle_segv函数中可以执行自定义的处理逻辑如打印调用栈信息、记录错误日志等。
请注意在实际的生产环境中对于空指针异常通常更好的做法是修复程序中的缺陷避免解引用空指针的情况发生而不是尝试捕捉并恢复。
小结 所有的信号都由操作系统来产生因为操作系统是进程的管理者 信号不是立即处理的而是在适合的情况进行处理
阻塞信号
信号在内核中的表示图 信号在Linux内核中的表示涉及到信号的三种状态抵达态、未决态和阻塞态也称为屏蔽态。 抵达态这是执行信号的处理动作的状态。也就是说当信号的处理动作被执行时信号就处于抵达态。抵达态下的信号处理方式有三种忽略、默认或执行自定义函数。 未决态这是从信号的产生到信号抵达之间的状态。当信号被发送但还未被进程处理时信号就处于未决态。这种状态下的信号在内核中会被记录等待处理。 阻塞态屏蔽态这是用户可以手动设置的状态。当信号处于阻塞态时即使信号已经产生也不会被立即处理而是保持未决状态。只有当用户解除了对该信号的阻塞屏蔽后信号才会转变为抵达状态执行相应的处理动作。
在内核中这三种状态通常使用结构体来存储每种状态对应一个结构体。这些结构体内部包含足够多的比特位每一个比特位对应一个信号值以此来记录和表示每个信号的状态。
另外Linux中的每个进程都拥有两个位向量pending位向量和blocked位向量。pending位向量包含了那些内核发送给进程但还没有被进程处理掉的信号而blocked位向量则包含了那些被进程屏蔽掉的信号。这两个位向量共同决定了进程将如何处理信号。
在信号处理机制中当内核发送一个信号给进程时它会修改进程的pending位向量。同样地当进程屏蔽掉一个信号时它会修改blocked位向量。只有当进程解除了对某个信号的屏蔽后如果pending位向量中对应该信号的值被设置为1表示该信号已产生且未处理那么该信号才会被递达给进程进行处理。
信号集操作函数
在Linux中信号集操作函数是用于操作信号集的一系列函数。信号集是一个包含多个信号的数据结构用于表示一组信号。这些函数提供了添加、删除、测试信号集中信号的功能以及用于阻塞和解除阻塞信号的功能。
下面是对这些函数的详细介绍和简单的示范代码 sigemptyset
sigemptyset函数用于初始化一个信号集将其所有位都设置为0即清空信号集。
#include signal.hint sigemptyset(sigset_t *set);示例
sigset_t emptyset;
sigemptyset(emptyset); // 将emptyset初始化为空信号集sigfillset
sigfillset函数用于将信号集中的所有位都设置为1即包含所有可能的信号。
#include signal.hint sigfillset(sigset_t *set);示例
sigset_t fullset;
sigfillset(fullset); // 将fullset初始化为包含所有信号的信号集sigaddset
sigaddset函数用于将一个指定的信号添加到信号集中。
#include signal.hint sigaddset(sigset_t *set, int signum);示例
sigset_t myset;
sigemptyset(myset);
sigaddset(myset, SIGINT); // 将SIGINT信号添加到myset信号集中sigdelset
sigdelset函数用于从信号集中删除一个指定的信号。
#include signal.hint sigdelset(sigset_t *set, int signum);示例
sigset_t myset;
sigfillset(myset);
sigdelset(myset, SIGINT); // 从myset信号集中删除SIGINT信号sigismember
sigismember函数用于检查一个指定的信号是否存在于信号集中。
#include signal.hint sigismember(const sigset_t *set, int signum);示例
sigset_t myset;
sigaddset(myset, SIGINT);
if (sigismember(myset, SIGINT)) {// SIGINT存在于myset信号集中
}sigprocmask
sigprocmask函数用于检查和/或更改当前进程的信号屏蔽字即阻塞的信号集。
#include signal.hint sigprocmask(int how, const sigset_t *set, sigset_t *oldset);how参数决定了如何更改信号屏蔽字SIG_BLOCK添加信号到当前阻塞集、SIG_UNBLOCK从当前阻塞集中移除信号或SIG_SETMASK设置当前阻塞集为指定的信号集。 set参数指向包含新信号集的指针。 oldset参数指向存储当前信号屏蔽字的指针或者为NULL。
示例
sigset_t blockset, oldset;
sigemptyset(blockset);
sigaddset(blockset, SIGINT);
sigprocmask(SIG_BLOCK, blockset, oldset); // 阻塞SIGINT信号sigpending
sigpending函数用于获取当前进程被阻塞的、但尚未处理的信号集。
#include signal.hint sigpending(sigset_t *set);示例
sigset_t pendingset;
sigpending(pendingset); // 获取当前进程的pending信号集注意在使用信号集操作函数时需要包含头文件signal.h。同时不同的操作可能需要不同的权限因此在某些情况下可能需要以root权限运行程序。
可重入函数
可重入函数示意图 可重入函数概念
可重入函数Reentrant Function是指在执行过程中可以被多个线程同时调用的函数且每个线程调用该函数时都会得到正确的结果不会因为其他线程的影响而导致数据混乱或错误。在多线程编程中使用可重入函数是非常重要的以确保线程安全。
可重入函数的使用
为了确保函数是可重入的通常需要注意以下几点 避免使用全局变量全局变量在多线程环境中可能导致数据竞争和不一致的结果。 避免使用静态局部变量静态局部变量在函数调用之间保持其值这可能导致线程间的数据混淆。 避免调用不可重入的函数如果函数调用了其他不可重入的函数那么该函数本身也将是不可重入的。 保护共享资源如果函数需要访问共享资源如文件、数据库等应使用适当的同步机制如互斥锁来确保同时只有一个线程可以访问。
下面是一个简单的可重入函数的示范代码
#include stdio.h
#include pthread.h// 这是一个可重入函数因为它不依赖任何全局或静态变量
int add(int a, int b) {return a b;
}// 线程函数它将调用可重入函数add
void* thread_func(void* arg) {int a *((int*)arg);int b 5;int result add(a, b);printf(Thread %ld: %d %d %d\n, (long)pthread_self(), a, b, result);return NULL;
}int main() {pthread_t threads[5];int values[] {1, 2, 3, 4, 5};// 创建5个线程每个线程都调用add函数for (int i 0; i 5; i) {pthread_create(threads[i], NULL, thread_func, (void*)values[i]);}// 等待所有线程完成for (int i 0; i 5; i) {pthread_join(threads[i], NULL);}return 0;
}在这个示例中add函数是一个可重入函数因为它只依赖于其参数并不使用任何全局或静态变量。thread_func是线程函数它调用了add函数。我们创建了5个线程每个线程都调用add函数但由于add是可重入的所以每个线程都会得到正确的结果而不会相互干扰。
volatile关键字
volatile关键字在C和C编程中尤其是在嵌入式系统和多线程编程中是一个非常重要的概念。在Linux编程中它同样扮演着重要角色。volatile告诉编译器不要对该变量进行任何优化每次访问这个变量时都应该直接从其内存地址中读取而不是使用寄存器中的值或进行其他可能的优化。
这是因为有些变量的值可能会在编译器无法检测到的情况下改变例如 硬件寄存器在嵌入式编程中我们可能会直接操作硬件寄存器这些寄存器的值可能会在任何时候由硬件改变。 多线程共享变量在多线程环境中一个线程可能会修改一个变量的值而另一个线程需要立即看到这个改变。 信号或中断服务例程在操作系统中中断服务例程可能会改变某些变量的值而这些改变是编译器无法预测的。
在这些情况下使用volatile可以确保每次访问变量时都会从内存中读取其最新值而不是使用编译器可能缓存的“旧”值。
示例代码
假设我们正在编写一个驱动程序该驱动程序需要读取一个硬件寄存器的值。
#include stdio.h// 假设这是一个硬件寄存器的地址
volatile int *hardware_register (volatile int*)0x12345678;int main() {int value;// 读取硬件寄存器的值value *hardware_register;printf(The value of the hardware register is: %d\n, value);return 0;
}在这个例子中hardware_register是一个指向硬件寄存器地址的指针并且它被声明为volatile。这意味着每次我们读取*hardware_register时都会直接从硬件寄存器中读取其值而不是使用任何可能的编译器优化或缓存的值。
需要注意的是volatile并不提供任何形式的原子性保证。在多线程环境中如果多个线程可能同时修改一个volatile变量那么仍然需要使用适当的同步机制如互斥锁或原子操作来确保数据的一致性。同样volatile也不能防止编译器重新排序读写操作。如果需要这些更高级的特性通常需要使用特定的编译器扩展或语言特性如C11中的_Atomic类型或C中的std::atomic。
SIGHLD信号
SIGHLD信号介绍
SIGCHLD信号的概念
SIGCHLD信号是一个在Unix和类Unix系统中用于通知父进程其子进程状态改变的信号。
SIGCHLD信号的作用
当子进程状态改变时父进程会收到SIGCHLD信号这使得父进程能够适当地清理子进程的资源例如回收僵尸进程。
SIGCHLD信号使用示例
示例代码实现
下面是一个简单的示例代码展示了如何使用SIGCHLD信号来回收子进程的资源。
#include stdio.h
#include stdlib.h
#include unistd.h
#include signal.h
#include sys/wait.h void handle_sigchld(int sig) { // 当收到SIGCHLD信号时这个函数会被调用 pid_t pid; int status; while ((pid waitpid(-1, status, WNOHANG)) 0) { // 使用WNOHANG标志来尝试非阻塞地等待子进程 // 如果成功回收了一个子进程waitpid会返回该子进程的PID // 如果没有子进程需要回收waitpid会返回0 // 如果发生错误waitpid会返回-1 printf(Child %d exited with status %d\n, pid, WEXITSTATUS(status)); }
} int main() { pid_t pid; struct sigaction sa; // 设置SIGCHLD信号的处理函数 sa.sa_handler handle_sigchld; sigemptyset(sa.sa_mask); sa.sa_flags 0; if (sigaction(SIGCHLD, sa, NULL) -1) { perror(sigaction); exit(EXIT_FAILURE); } // 创建子进程 pid fork(); if (pid -1) { perror(fork); exit(EXIT_FAILURE); } else if (pid 0) { // 子进程代码 printf(Child process (PID %d) running...\n, getpid()); sleep(2); // 子进程休眠2秒 printf(Child process exiting...\n); exit(42); // 子进程以状态码42退出 } else { // 父进程代码 printf(Parent process (PID %d) waiting for child...\n, getpid()); // 父进程可以继续执行其他任务当子进程退出时SIGCHLD信号会被发送并处理 } // 父进程等待一段时间以确保子进程有机会运行和退出 sleep(5); return 0;
}示例代码解释 信号处理器设置
定义了一个名为handle_sigchld的函数作为SIGCHLD信号的处理器。该函数会在收到SIGCHLD信号时被调用并尝试非阻塞地回收子进程。 子进程创建与退出
在main函数中使用fork创建了一个子进程。子进程执行一些操作后以特定的状态码退出。 父进程等待与处理
父进程等待一段时间以便子进程有机会运行和退出。当子进程退出时父进程会收到SIGCHLD信号并调用之前设置的信号处理器函数handle_sigchld来回收子进程资源。
示例代码总结
通过示例代码展示了如何使用SIGCHLD信号来异步地回收子进程资源避免了僵尸进程的问题。在实际应用中可以根据具体需求调整代码以适应不同场景。