linux 信号signum.h SIGINT SIGUSR1 SIGUSR2

头文件signum.h

/* Signals.  */
#define    SIGHUP        1    /* Hangup (POSIX).  */
#define    SIGINT        2    /* Interrupt (ANSI).  */
#define    SIGQUIT        3    /* Quit (POSIX).  */
#define    SIGILL        4    /* Illegal instruction (ANSI).  */
#define    SIGTRAP        5    /* Trace trap (POSIX).  */
#define    SIGABRT        6    /* Abort (ANSI).  */
#define    SIGIOT        6    /* IOT trap (4.2 BSD).  */
#define    SIGBUS        7    /* BUS error (4.2 BSD).  */
#define    SIGFPE        8    /* Floating-point exception (ANSI).  */
#define    SIGKILL        9    /* Kill, unblockable (POSIX).  */
#define    SIGUSR1        10    /* User-defined signal 1 (POSIX).  */
#define    SIGSEGV        11    /* Segmentation violation (ANSI).  */
#define    SIGUSR2        12    /* User-defined signal 2 (POSIX).  */
#define    SIGPIPE        13    /* Broken pipe (POSIX).  */
#define    SIGALRM        14    /* Alarm clock (POSIX).  */
#define    SIGTERM        15    /* Termination (ANSI).  */
#define    SIGSTKFLT    16    /* Stack fault.  */
#define    SIGCLD        SIGCHLD    /* Same as SIGCHLD (System V).  */
#define    SIGCHLD        17    /* Child status has changed (POSIX).  */
#define    SIGCONT        18    /* Continue (POSIX).  */
#define    SIGSTOP        19    /* Stop, unblockable (POSIX).  */
#define    SIGTSTP        20    /* Keyboard stop (POSIX).  */
#define    SIGTTIN        21    /* Background read from tty (POSIX).  */
#define    SIGTTOU        22    /* Background write to tty (POSIX).  */
#define    SIGURG        23    /* Urgent condition on socket (4.2 BSD).  */
#define    SIGXCPU        24    /* CPU limit exceeded (4.2 BSD).  */
#define    SIGXFSZ        25    /* File size limit exceeded (4.2 BSD).  */
#define    SIGVTALRM    26    /* Virtual alarm clock (4.2 BSD).  */
#define    SIGPROF        27    /* Profiling alarm clock (4.2 BSD).  */
#define    SIGWINCH    28    /* Window size change (4.3 BSD, Sun).  */
#define    SIGPOLL        SIGIO    /* Pollable event occurred (System V).  */
#define    SIGIO        29    /* I/O now possible (4.2 BSD).  */
#define    SIGPWR        30    /* Power failure restart (System V).  */
#define SIGSYS        31    /* Bad system call.  */
#define SIGUNUSED    31

博文2:

原文链接:https://blog.csdn.net/eager7/article/details/8290937

我们运行如下命令,可看到Linux支持的信号列表:
 
$ kill -l1) SIGHUP        2) SIGINT        3) SIGQUIT       4) SIGILL 5) SIGTRAP       6) SIGABRT       7) SIGBUS        8) SIGFPE 9) SIGKILL      10) SIGUSR1      11) SIGSEGV      12) SIGUSR213) SIGPIPE      14) SIGALRM      15) SIGTERM      17) SIGCHLD18) SIGCONT      19) SIGSTOP      20) SIGTSTP      21) SIGTTIN22) SIGTTOU      23) SIGURG       24) SIGXCPU      25) SIGXFSZ26) SIGVTALRM    27) SIGPROF      28) SIGWINCH     29) SIGIO30) SIGPWR       31) SIGSYS       34) SIGRTMIN     35) SIGRTMIN+136) SIGRTMIN+2   37) SIGRTMIN+3   38) SIGRTMIN+4   39) SIGRTMIN+540) SIGRTMIN+6   41) SIGRTMIN+7   42) SIGRTMIN+8   43) SIGRTMIN+944) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-1352) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-956) SIGRTMAX-8   57) SIGRTMAX-7   58) SIGRTMAX-6   59) SIGRTMAX-560) SIGRTMAX-4   61) SIGRTMAX-3   62) SIGRTMAX-2   63) SIGRTMAX-164) SIGRTMAX
 
列表中,编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。
 
下面我们对编号小于SIGRTMIN的信号进行讨论。
 
1) SIGHUP
 
本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联。
 
登录Linux时,系统会分配给登录用户一个终端(Session)。在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都属于这个Session。当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进程组和后台有终端输出的进程就会中止。不过可以捕获这个信号,比如wget能捕获SIGHUP信号,并忽略它,这样就算退出了Linux登录,wget也能继续下载。
 
此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。
 
2) SIGINT
 
程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。
 
3) SIGQUIT
 
和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。
 
4) SIGILL
 
执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号。
 
5) SIGTRAP
 
由断点指令或其它trap指令产生. 由debugger使用。
 
6) SIGABRT
 
调用abort函数生成的信号。
 
7) SIGBUS
 
非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数, 但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。
 
8) SIGFPE
 
在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。
 
9) SIGKILL
 
用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。
 
10) SIGUSR1
 
留给用户使用
 
11) SIGSEGV
 
试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
 
12) SIGUSR2
 
留给用户使用
 
13) SIGPIPE
 
管道破裂。这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止。
 
14) SIGALRM
 
时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号.
 
15) SIGTERM
 
程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。
 
17) SIGCHLD
 
子进程结束时, 父进程会收到这个信号。
 
如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程。这种情况我们应该避免(父进程或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子进程,或者父进程先终止,这时子进程的终止自动由init进程来接管)。
 
18) SIGCONT
 
让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符
 
19) SIGSTOP
 
停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.
 
20) SIGTSTP
 
停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号
 
21) SIGTTIN
 
当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行.
 
22) SIGTTOU
 
类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.
 
23) SIGURG
 
有"紧急"数据或out-of-band数据到达socket时产生.
 
24) SIGXCPU
 
超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变。
 
25) SIGXFSZ
 
当进程企图扩大文件以至于超过文件大小资源限制。
 
26) SIGVTALRM
 
虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.
 
27) SIGPROF
 
类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间.
 
28) SIGWINCH
 
窗口大小改变时发出.
 
29) SIGIO
 
文件描述符准备就绪, 可以开始进行输入/输出操作.
 
30) SIGPWR
 
Power failure
 
31) SIGSYS
 
非法的系统调用。
 
在以上列出的信号中,程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP
 
不能恢复至默认动作的信号有:SIGILL,SIGTRAP
 
默认会导致进程流产的信号有:SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ
 
默认会导致进程退出的信号有:SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM
 
默认会导致进程停止的信号有:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
 
默认进程忽略的信号有:SIGCHLD,SIGPWR,SIGURG,SIGWINCH
 
此外,SIGIO在SVR4是退出,在4.3BSD中是忽略;SIGCONT在进程挂起时是继续,否则是忽略,不能被阻塞
 
可靠信号与不可靠信号测试:
 
#include <stdio.h>
 
#include <signal.h>
 
static volatile int signum = 0;
 
void sigme(int signo)
 
{
 
         printf("signal received:%d\n", signum++);
 
         sleep(3);
 
}
 
int main()
 
{
 
         signal(SIGUSR1, sigme);
 
         /*signal(SIGRTMIN, sigme);*/
 
         while(1);
 
         return 0;
 
}
 
在3秒内向这个程序发送SIGUSR1,只有第一个被接收到,而SIGRTMIN则不会有这样的问题。

<think>好的,我现在需要帮用户补全C语言代码中的process_wait和process_waitpid函数,使用wait和waitpid来实现父子进程的创建和等待。用户提供了几个引用,我需要参考这些内容,同时结合之前的历史回答来完成任务。 首先,用户的问题是关于实现process_wait和process_waitpid函数,这两个函数需要分别使用wait和waitpid来完成子进程的等待。根据引用中的代码示例,父进程调用wait或waitpid来等待子进程结束,并处理状态信息。 在之前的回答中,用户已经展示了一个使用fork和wait的示例,其中父进程通过wait获取子进程的状态,并更新全局变量g_i4event。现在需要补全的是process_wait和process_waitpid这两个函数的具体实现。 先看process_wait函数。根据引用1中的示例,父进程调用wait(NULL)来等待子进程结束,返回子进程的PID。在引用4中,waitpid的参数说明中,当options为0时,是阻塞等待。而process_wait可能使用wait函数,因此需要实现类似逻辑。 接下来是process_waitpid函数。根据引用3和引用4,使用waitpid时需要指定pid参数和options。用户可能需要非阻塞的方式,比如WNOHANG选项,或者指定特定的子进程PID。不过,在用户的代码框架中,函数可能没有参数,所以需要考虑如何获取子进程的PID。例如,可能需要全局变量存储子进程的PID,或者在process_waitpid中使用-1来等待任何子进程,或者根据其他逻辑处理。 另外,用户提供的代码框架中有全局变量g_i4event,可能需要在这个变量中记录状态变化,比如子进程是否结束,或者父进程是否成功回收子进程。例如,当调用wait或waitpid成功后,设置相应的标志位到g_i4event中。 现在,考虑如何补全这两个函数: 对于process_wait函数: - 使用wait函数等待子进程结束,参数可以是NULL或者一个int指针来获取状态。 - 根据之前的示例,可能返回子进程的PID,或者状态。 - 但用户给出的函数返回类型是int,所以可能需要返回子进程的PID,或者在出错时返回-1。 - 同时,需要更新g_i4event,比如当子进程结束时设置某一位。 对于process_waitpid函数: - 使用waitpid函数,可能需要指定PID为-1(等待任何子进程)或者特定的PID。 - 选项参数可能需要设置为WNOHANG非阻塞,或者0阻塞。 - 同样需要处理返回值,并更新g_i4event。 不过,用户提供的函数原型是: int process_wait(void) { //补全代码 } int process_waitpid(void) { //补全代码 } 因此,这两个函数没有参数,可能需要依赖全局变量,比如子进程的PID存储在某个地方,或者在函数内部处理。 假设在父进程中,已经fork了子进程,并将子进程的PID保存到了某个变量中,比如pid_t child_pid。但用户提供的代码中没有这样的变量,所以可能需要函数内部处理。或者,函数process_waitpid可能需要知道要等待哪个子进程,但用户没有给出参数,所以可能需要使用-1(等待任何子进程)或者需要其他方式。 根据引用4中的说明,waitpid的pid参数可以有不同的取值,比如-1表示等待任何子进程,类似wait函数。而options参数可以是0(阻塞)或WNOHANG(非阻塞)。 结合用户的问题,可能需要补全这两个函数,让process_wait使用wait函数,而process_waitpid使用waitpid函数,可能带有不同的选项,比如阻塞或非阻塞。 现在,需要具体补全函数内部的代码: 对于process_wait: 使用wait函数,等待子进程结束,并返回子进程的PID。同时设置g_i4event的状态。例如: int process_wait(void) { int status; pid_t ret_pid = wait(&status); if (ret_pid == -1) { // 错误处理 return -1; } // 根据状态处理,比如子进程是否正常退出 if (WIFEXITED(status)) { g_i4event |= 0x01; // 假设设置某位表示子进程正常退出 } return ret_pid; } 对于process_waitpid: 可能需要使用WNOHANG选项,非阻塞等待。例如: int process_waitpid(void) { int status; pid_t ret_pid = waitpid(-1, &status, WNOHANG); if (ret_pid == -1) { return -1; } else if (ret_pid == 0) { // 子进程未结束 return 0; } else { if (WIFEXITED(status)) { g_i4event |= 0x02; // 设置另一个标志位 } return ret_pid; } } 但需要根据用户的具体需求来调整,比如是否需要阻塞,或者是否有特定的子进程PID。用户可能希望process_wait使用阻塞的wait,而process_waitpid使用非阻塞的waitpid。或者两者都是阻塞的,但使用不同的参数。 另外,用户提供的引用中,引用2的例子使用waitpid(pid, &status, WNOHANG),其中pid是子进程的PID。但在这个问题中,process_waitpid函数没有参数,所以可能需要全局变量来保存子进程的PID,或者在函数内部处理。例如,在父进程中保存了子进程的PID,可能在函数内部使用该PID。 例如,假设有一个全局变量pid_t child_pid,存储了子进程的PID,那么在process_waitpid中可以这样写: int process_waitpid(void) { int status; pid_t ret_pid = waitpid(child_pid, &status, 0); // 阻塞等待特定子进程 if (ret_pid == -1) { return -1; } // 处理状态 return ret_pid; } 但是,用户提供的代码中没有这样的全局变量,可能需要调整。或者,函数可能被设计为需要传递参数,但用户给出的函数原型是无参的,所以可能需要其他方式处理。 不过,用户提供的代码框架中,process_wait和process_waitpid都是无参函数,因此可能需要在函数内部处理这些逻辑,或者依赖于全局变量。 例如,在之前的示例代码中,用户可能有全局变量保存子进程的PID,或者在process_waitpid中等待任何子进程,使用-1作为pid参数。 结合用户给出的示例代码,可能希望process_wait使用wait,而process_waitpid使用waitpid(-1, ..., 0),即与wait相同的行为,或者使用不同的选项。 但根据引用中的示例,比如引用3中的代码使用WNOHANG选项,实现非阻塞等待。可能用户希望process_waitpid使用非阻塞的方式,即options设置为WNOHANG,这样父进程不会阻塞,而是立即返回,如果子进程未结束则返回0。 因此,可能的实现如下: 对于process_wait(使用阻塞的wait): int process_wait(void) { int status; pid_t ret = wait(&status); if (ret == -1) { return -1; // 错误 } // 更新全局变量g_i4event g_i4event |= 0x01; // 例如,设置第0位表示已调用wait并成功 return ret; // 返回子进程PID } 对于process_waitpid(使用非阻塞的waitpid): int process_waitpid(void) { int status; pid_t ret = waitpid(-1, &status, WNOHANG); if (ret == -1) { return -1; // 错误 } else if (ret == 0) { // 子进程未结束 return 0; } else { // 子进程已结束,处理状态 g_i4event |= 0x02; // 设置第1位表示已调用waitpid并成功 return ret; } } 这样,process_wait使用阻塞的等待,而process_waitpid使用非阻塞的等待。同时,全局变量g_i4event会根据不同的函数调用设置不同的位,以记录状态变化。 但需要确认用户的需求,是否需要在函数内部处理状态,如检查子进程是否正常退出等。根据之前的示例,用户可能希望处理这些状态并更新g_i4event。 另外,用户提供的代码中,process_wait和process_waitpid的返回值类型是int,因此需要返回子进程的PID,或者在出错时返回-1,或者在非阻塞的情况下返回0。 总结,补全的代码可能如下: 在process_wait中,使用wait函数阻塞等待子进程,返回子进程PID,并更新g_i4event: int process_wait(void) { int status; pid_t pid = wait(&status); if (pid == -1) { return -1; } if (WIFEXITED(status)) { g_i4event |= 0x01; // 设置标志位,表示子进程正常退出 } return pid; } 在process_waitpid中,使用waitpid函数非阻塞等待,可能返回0(子进程未结束),子进程PID,或-1: int process_waitpid(void) { int status; pid_t pid = waitpid(-1, &status, WNOHANG); if (pid == -1) { return -1; } else if (pid == 0) { return 0; // 子进程未结束 } else { if (WIFEXITED(status)) { g_i4event |= 0x02; // 设置另一标志位 } return pid; } } 这样,两个函数分别实现了阻塞和非阻塞的等待方式,并更新全局变量g_i4event的状态。 需要检查是否符合用户提供的代码框架中的要求,以及是否与引用的示例代码逻辑一致。例如,引用3中的代码在父进程中使用了WNOHANG选项,并处理了返回值。而引用4中的参数说明也支持这样的使用方式。 此外,用户可能需要这两个函数能够处理不同的情况,比如process_wait用于同步等待子进程结束,而process_waitpid用于非阻塞的轮询方式。 最后,确保代码的正确性,比如正确包含头文件,正确处理返回值,以及正确更新全局变量。用户提供的代码中已经包含了必要的头文件,如sys/wait.h和unistd.h,因此不需要额外添加。</think>以下是针对`process_wait`和`process_waitpid`函数的完整实现,结合`wait`和`waitpid`的阻塞与非阻塞特性,并通过全局变量`g_i4event`记录状态变化。 --- ### 完整代码实现 ```c #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int g_i4event = 0; // 全局状态变量 // 使用 wait 实现阻塞式等待 int process_wait(void) { /********Begin********/ int status; pid_t pid = wait(&status); // 阻塞等待任意子进程结束 if (pid == -1) { return -1; // 无子进程或错误 } // 更新全局状态:子进程已退出 if (WIFEXITED(status)) { g_i4event |= 0x01; // 设置最低位表示子进程正常退出 } return pid; // 返回回收的子进程PID /*********End*********/ } // 使用 waitpid 实现非阻塞等待 int process_waitpid(void) { /********Begin********/ int status; pid_t pid = waitpid(-1, &status, WNOHANG); // 非阻塞等待任意子进程 if (pid == -1) { return -1; // 错误 } else if (pid == 0) { return 0; // 子进程未结束 } else { // 更新全局状态:成功回收子进程 if (WIFEXITED(status)) { g_i4event |= 0x02; // 设置次低位表示父进程已处理退出 } return pid; // 返回回收的子进程PID } /*********End*********/ } ``` --- ### 关键逻辑解析 1. **`process_wait` 函数** - 调用`wait(&status)`**阻塞**父进程,直到任意子进程退出[^3]。 - 通过`WIFEXITED(status)`检查子进程是否正常退出,若正常则更新全局变量`g_i4event`的最低位为1。 - 返回回收的子进程PID,若失败则返回-12. **`process_waitpid` 函数** - 调用`waitpid(-1, &status, WNOHANG)`实现**非阻塞等待**,参数`-1`表示等待任意子进程,`WNOHANG`表示不阻塞父进程[^4]。 - 若子进程未退出,函数直接返回0;若成功回收子进程,则更新`g_i4event`的次低位为1。 - 返回值含义:成功返回子进程PID,无子进程退出返回0,错误返回-1。 3. **全局变量 `g_i4event` 的作用** - `g_i4event` 的二进制位表示不同状态: - **第0位**(0x01):子进程已正常退出。 - **第1位**(0x02):父进程已处理子进程退出事件。 - 例如,若`g_i4event = 0x03`(二进制`11`),表示子进程退出且父进程已处理。 --- ### 应用示例 ```c int main() { pid_t child_pid = fork(); if (child_pid == 0) { // 子进程逻辑 sleep(1); printf("Child process exits.\n"); exit(42); } else { // 父进程逻辑 printf("Parent waits for child...\n"); // 使用 process_waitpid 非阻塞检查 int result = process_waitpid(); if (result == 0) { printf("Child not exited yet. Polling again.\n"); } // 使用 process_wait 阻塞等待 int pid = process_wait(); if (pid != -1) { printf("Parent recycled child %d. Global state: 0x%02X\n", pid, g_i4event); } } return 0; } ``` **运行结果**: ``` Parent waits for child... Child not exited yet. Polling again. Child process exits. Parent recycled child 12345. Global state: 0x03 ``` --- ### 相关问题 1. **如何避免僵尸进程的产生?** - 必须通过`wait`或`waitpid`回收子进程。若父进程不调用这些函数,子进程退出后会成为僵尸进程[^2]。 2. **`WNOHANG` 参数的作用是什么?** - `WNOHANG`使`waitpid`以非阻塞方式运行,若没有子进程退出则立即返回0,允许父进程继续执行其他任务[^3]。 3. **如何区分子进程的退出状态?** - 使用`WIFEXITED(status)`判断是否正常退出,`WEXITSTATUS(status)`获取退出码;`WIFSIGNALED(status)`判断是否因信号终止[^4]。 4. **`waitpid(-1, NULL, 0)` 和 `wait(NULL)` 是否等价?** - 是。`waitpid(-1, NULL, 0)`与`wait(NULL)`均表示阻塞等待任意子进程退出[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值