共 1 篇文章

标签:Linux 信号 注册 注销 阻塞

Linux中的信号(注册,注销,处理,阻塞)-国外主机测评 - 国外VPS,国外服务器,国外云服务器,测评及优惠码

Linux中的信号(注册,注销,处理,阻塞)

Linux中的信号(注册,注销,处理,阻塞)  更新时间:2024年02月12日 17:04:22   作者:风吹雨淋   这篇文章主要介绍了Linux中的信号(注册,注销,处理,阻塞),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教 目录 信号注册 信号注销 信号处理 信号阻塞 PCB如何获取signal函数使用自定义信号 sigaction函数 可重入函数 volatile关键字 sigchld 总结 未决:pending(汉语翻译:待定,即将发生) 信号产生但没有被处理,pending表0变1,表示进程收到对应信号(准确的来说叫信号写入) 阻塞,为了拦截对应信号做出对应的处理动作。不想处理某些信号,拦不住别人给进程发 信号待定是可以随时递达(被处理),如果没有被阻塞,信号会在合适的时候递达(被处理) 什么叫合适的时候:从内核态切换到用户态时进行信号的检测和处理 如果信号阻塞,该信号永远处于未决状态 总之pending表就是随时能处理信号,一旦设置了阻塞,只有解除阻塞才能处理信号 信号注册 信号注册:在进程中做标记,让进程能够知道自己收到某个信号,官方说法操作系统内核给进程发送信号的过程,这个过程称为注册 PCB中有一个pending未决(没有被处理)信号的集合(是一个位图结构),标记进程收到了某个信号 PCB中有一个sigqueue链表(实质是一个双向链表),进程每收到一个信号,就是给该链表中添加一个对应信号的节点,并且修改位图,将信号值对应位置置1 非可靠信号注册: 如果没有收到信号则注册(添加节点,位图置1) 如果之前收到了信号还未处理,则什么都不做(丢弃) 可靠信号注册: 不管位图是否置1(是否已经注册,还没处理),都会添加一个信号节点 可以通过sigqueue函数在发送信号的同时携带数据 信号注销 什么是注销: 在信号被处理之前,消除信号存在的痕迹 主要防止信号被重复处理 非可靠信号的注销: 删除信号的信息节点,位图置0 可靠信号的注销: 删除信号的一个信息节点,当前没有相同节点则位图置0 信号处理 处理就是调用信号的处理函数 有三种处理方式 默认处理:系统中已经定义好了处理方式 忽略处理:空的处理方式 SIGCHLD:子进程再退出时给父进程发送一个SIGCHLD信号,父进程对于该信号的处理方式是忽略处理 该信号对于所有进程而言都是忽略处理 自定义处理:自己定义一个处理函数,替换掉处理函数 自定义处理函数signal 用handler函数,替换signum信号当前的处理函数 自定义信号的捕捉流程(捕捉流程:从用户态进入内核态,找到信号并处理的过程) 进入内核的原因: 系统调用函数 中断 进程异常 当前执行流在用户态收到信号,不能立即处理信号,而是从用户态切换到内核态时处理 进入内核后,执行流并不知道要处理信号,而是执行一些功能当要从内核态返回到用户态,一定会调用do_signal函数判断当前进程有无收到信号,收到则立即处理,没有直接返回到用户态 如果有信号就执行信号对应动作 如果是自定义处理方式,会从内核态切换到用户态执行自定义函数,调用sigreturn函数再次进入到内核(不能以内核身份执行用户写的自定义代码) 再去调用dosignal判断是否有其它信号需要处理 信号阻塞 阻塞(阻塞不是在处理信号) 信号被阻塞后依然会注册,但是暂时不处理(直到被解除阻塞) PCB中有个block阻塞信号集合,哪个信号被添加到block阻塞集合中,表示收到信号但暂时不处理 更改或获取进程的信号block表(将信号集合设置进内核) int sigprocmask(int how, const sigset_t* set, sigset_t* oset) how:对PCB中信号阻塞集合进行的操作 SIG_BLOCK:block|=set 把set集合中的信号添加到block集合中,阻塞set集合中的信号 SIG_UNBLOCK:block&=~set 解除 SIG_SETMASK:block=set 重新设置block表 oldset将修改前block集合中的信息添加到old中,便于还原 是输出型参数,将原block返回,不想返回设置为NULL 要屏蔽2号信号,将2号信号添加到set中 set是输入型参数 函数在阻塞指定信号时,就要传进去一个集合, 意味着要将所有的信号添加到一个集合中 所以要先定义一个信号集合的变量sigset_t 通过sigsetempty(sigset* set)先将集合中的数据清空 通过sigaddset(sigset_t* set, int sugnum)—-将signum添加到set集合中(单个添加) 通过sigfillset(sigset_t *set)————————将所有信号添加到set中 通过sigdelset(sigset_t *set, int signum)—-移除指定信号 通过sigismember(sigset_t *set, int signum)–按段信号signum是(返回1)否(-1)在set信号集合中 9号和19号不能被阻塞,忽略,自定义 僵尸进程是已经死了的 SIGPIPE 管道读端关闭,继续写,会在write会触发异常 SIGCHLD 子进程退出时给父进程发送的信号 这个信号的默认处理方式是忽略,因此未对子进程退出做出处理 修改SIGCHLD的默认处理方法(让回调函数内部wait子进程)其实并不合理 因为该信号是非可靠信号,大量子进程同时退出,发出的多个非可靠信号可能只注册了一次 可直接显示忽略,明确告诉OS,子进程退出我不关心,直接把资源回收 signal(SIGCHLD, SIG_IGN) 或者在回调函数内部,使用waitpid循环等待每一个子进程退出的信号 int...

技术分享