目录
一,信号的产生
1,终端按键
2,调用系统函数向进程发送信号
(1)、kill:给指定的进程发送指定的命令
(2)、raise:自己给自己发信号
(3)、abort:让当前进程收到信号异常终止
3,由硬件产生
(1)、比如除零错误,
4、由软件条件产生
(1)、alarm:闹钟,
(2)、重置闹钟
(3)、修改闹钟
二,信号的捕捉
1、信号捕捉函数
三、信号概念
1、信号再内核中的表示
2、信号未决
3、信号递达
3、阻塞信号
四、信号集处理
1,信号集:sigset_t
2、信号集处理函数
(1)、int sigemptyset(sigset_t *set);
(2)、int sigfillset(sigset_t *set);
(3)、int sigaddset (sigset_t *set, int signo);
(4)、int sigdelset(sigset_t *set, int signo);
(5)、int sigismember(const sigset_t *set, int signo);
(6)、int sigprocmask(int how, const sigset_t *set, sigset_t *oset):
(7)、int sigpending(sigset_t *set);
3、内核如何信号捕捉
(1)、sigaction
4.SIGCHLD信号
(1)、子进程退出发信号
(2)、不用等待的方式回收子进程
一,信号的产生
1,终端按键
比如Ctrl +c 杀掉进程
2,调用系统函数向进程发送信号
(1)、kill:给指定的进程发送指定的命令
这是一个死循环,我们通过kill命令行发送9号信号,杀死进程,
调用kill函数
后面死循环不执行,直接退出
(2)、raise:自己给自己发信号
自己给自己发送9号信号,当然也可以发送其他信号
(3)、abort:让当前进程收到信号异常终止
也是通过发送信号终止程序,具体发送了几号信号,可以再后面的信号捕捉中验证。
3,由硬件产生
硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。
(1)、比如除零错误,
我们学c++遇到进程直接就直接终止了,那为什么呢?今天我们就知道了。其实是收到了信号。
直接退出了,因为除零错误对应发送的信号默认就是结束进程。
4、由软件条件产生
(1)、alarm:闹钟,
指定时间后退出进程。
(2)、重置闹钟
时间不到的话,充值alarm(0):取消闹钟
闹钟取消,不退出了。
(3)、修改闹钟
二,信号的捕捉
1、信号捕捉函数
捕捉Ctrl+c。也就是2好信号,默认处理方法就不在是退出进程了。
三、信号概念
1、信号再内核中的表示
俩个个位图,分表表示阻塞,未决,0表示没有设置,1表示设置。
第三个是一个指针数据,保存的是对应信号的处理方法。
内核再发信号是只需要把对应oppending位图的对应位置设置为1就算发送了。
内核阻塞信号也是一样的,把block位图对应位置设置为1.
2、信号未决
信号从产生到递达之间的状态,称为信号未决(Pending)。
也就是说信号产生了,因为某种原因,还没有开始处理这个信号。
3、信号递达
信号产生,并且以及实际执行信号的处理动作称为(Delivery)。
3、阻塞信号
(1)、进程可以选择阻塞 (Block )某个信号。
(2)、被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
(3)、注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
四、信号集处理
1,信号集:sigset_t
本质上是一个整形,但是看实现把,不要直接操作他,每个二进制表示一个对应信号状态。
2、信号集处理函数
(1)、int sigemptyset(sigset_t *set);
初始化信号集,所有bit位清零。
(2)、int sigfillset(sigset_t *set);
初始化所有的信号集,每个bit位都搞成有效的。
(3)、int sigaddset (sigset_t *set, int signo);
给信号集调价对应的信号。
(4)、int sigdelset(sigset_t *set, int signo);
给信号集删除指定的信号设置。
(5)、int sigismember(const sigset_t *set, int signo);
判断信号集中是否有有效信号。
(6)、int sigprocmask(int how, const sigset_t *set, sigset_t *oset):
how表示如何修改:
SIG_BLOCK:添加set进入当前的信号屏蔽字。
SIG_UNBLOCK:检出set中的信号屏蔽字。
SIG_SETMASK:设置set为当前的信号屏蔽字。
用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集);
oset是带回原来的信号屏蔽子设置,万一将来向恢复也是可以的,不需要传nullptr。
(7)、int sigpending(sigset_t *set);
读取当前进程的信号未决信号集.输出形参数,通过set把结果带回来。
我们这几一个函数showpprint获取当前信号的未决信号集,我们阻塞1-31号信号,发现信号都不能递达了,但是9号信号这里任然递达了,这说明不是所有的信号都是可以被阻塞的,因为那样也太bug了。因为我阻塞了所有信号,岂不是我没有办法被杀死了,那万一我是木马病毒呢、
结果:
我们看看是否成功阻塞了1-31信号。
发现是可以的,但是9号信号任然不可以,如上解释。
3、内核如何信号捕捉
如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下: 用户程序注册了SIGQUIT信号的处理函数sighandler。 当前正在执行main函数,这时发生中断或异常切换到内核态。 在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函 数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是 两个独立的控制流程。 sighandler函数返
回后自动执行特殊的系统调用sigreturn再次进入内核态。 如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了.
(1)、sigaction
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
sigaction函数可以读取和修改与指定信号相关联的处理动作。成功返回0,失败返回-1.signo
是指定信号的编号。若act指针非空,则根据act修改该信号的处理动作。若oact指针非 空,则通过oact传出该信号原来的处理动作。act和oact指向sigaction结构体:
用的时候看系统给出的结构体就比较明了了,不需要去记忆.
将sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号,赋值为常数SIG_DFL表示执行系统默认动作,赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函 数,该函数返回值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以用同一个函数处理多种信号。显然,这也是一个回调函数,不是被main函数调用,而是被系统所调用。
当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止。 如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。 sa_flags字段包含一些选项,sa_flags设为0,sa_sigaction是实时信号的处理函数.
自定义4、5信号的处理动作的同时阻塞8、6信号的处理、
我们发现是可以的,这样就避免了对一批信号自定义捕捉同一个方法的时候写一批信号捕捉数。
我们发现效果是可以的。
4.SIGCHLD信号
(1)、子进程退出发信号
子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自 定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程 终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。
但是:但是这里不是简单的一个wait,因为信号处理时,该信号是默认阻塞的,同时发信号处理不干净,所以要加上循环,判断等进行非阻塞的处理,注意这里一定是非阻塞,不然主函数出去可能就回不来了,子进程不退出就一直再信号处理函数那里等了。非阻塞没事,等子进程退出了发信号,父亲进程再去处理等待。
代码:
我们来看结果,子进程退出确实给父进程发送了SIGCHLD信号。
(2)、不用等待的方式回收子进程
我们发现,这样写子进程就算同时退出同时给父进程发送SIGCHLD信号也是没有事情的。
如果父进程再等待的时候子进程还没有退出,父进程就退出忙自己的事情了,等那个子进程退出了父进程再去等待,假设多个子进程同时发送SIGCHID信号,父进程等待子进程那里有循环的,也是不怕的。所以这个代码目前来说感觉是可以所有情况的子进程回收问题,父进程不用阻塞等待,也不需要设计轮寻等待的方式来不让父进程阻塞等待。感觉是挺好的。