附近做网站的公司,app模板素材,百度联盟怎么做网站加入,一个专门做预告片的网站上次介绍了#xff1a;(Linux#xff1a;进程信号#xff08;一.认识信号、信号的产生及深层理解、Term与Core#xff09;)[https://blog.csdn.net/qq_74415153/article/details/140624810] 文章目录 1.信号保存1.1递达、未决、阻塞等概念1.2再次理解信号产生与保存1.3信号…上次介绍了(Linux进程信号一.认识信号、信号的产生及深层理解、Term与Core)[https://blog.csdn.net/qq_74415153/article/details/140624810] 文章目录 1.信号保存1.1递达、未决、阻塞等概念1.2再次理解信号产生与保存1.3信号集操作函数sigset_t类型sigprocmask系统调用sigpending系统调用  2.信号的处理/递达2.1信号处理时机与过程2.2用户态和内核态2.3再看进程地址空间谁来运行OS 2.4信号的捕捉—sigaction()函数 3.补充知识3.1可重入函数3.2volatile关键字3.3 SIGCHLD信号  1.信号保存 
1.1递达、未决、阻塞等概念 信号未决Pending当信号产生时会首先进入未决状态即信号还没有被进程处理。此时信号被标记为未决状态等待进程处理。  信号递达Delivery当进程解除对信号的阻塞时信号才会被递达即信号被传递给进程的信号处理函数进行处理。  三种信号处理方式  默认处理Default Handling每个信号都有一个默认的处理方式当信号递达时操作系统会执行默认的信号处理动作传入SIG_DFL  自定义处理Custom Handling进程可以通过设置信号处理函数一般是handler来自定义对信号的处理方式。当信号递达时操作系统会调用进程设置的信号处理函数来处理信号  忽略处理Ignore Handling进程还可以选择忽略某个信号即在信号递达时不做任何处理。通过将信号处理函数设置为 SIG_IGN进程可以忽略某个信号    阻塞信号进程可以选择阻塞某个或多个信号使其在未决状态下等待。被阻塞的信号不会递达保持在未决状态直到进程解除对此信号的阻塞  
1.2再次理解信号产生与保存 
在操作系统中进程信号相关的Pending位图和Block位图是两种数据结构用于跟踪进程当前挂起/未决pending的信号和已经阻塞blocked的信号 Pending位图 作用Pending位图用于记录当前对进程发送但尚未被处理的信号。当操作系统向进程发送信号时如果进程当前不能立即处理该信号比如正在处理其他信号或忙于执行其他任务该信号会被添加到进程的Pending位图中。操作操作系统会定期检查进程的Pending位图并根据信号处理方式默认处理、自定义处理、忽略处理来决定如何处理挂起的信号。  Block位图 作用Block位图用于记录当前被阻塞的信号。进程可以选择阻塞某些信号使得这些信号被阻塞不会被递送给进程。操作当信号被阻塞时该信号会被添加到进程的Block位图中。被阻塞的信号不会被递送给进程直到解除阻塞。特点Block位图记录了进程当前被阻塞的信号帮助进程控制哪些信号可以递送到进程。  其中信号的阻塞与否跟是否收到信号毫无关系 对应信号在进程的信号未决位图中的比特位会在信号递达前被设置为1表示信号需要处理而在信号被处理完后会被清零即改为0 是先清0再进行递达 而进程能识别信号也是因为早在未收到信号之前我们就已经知道是否堵塞怎么处理了利用上述三个表 信号处理表在进程创建时内核会为其分配一个信号处理表用于记录每个信号对应的信号处理函数Signal Handler。当进程收到一个信号时内核会根据信号处理表中对应信号的处理函数来执行相应的操作。信号未决位图在进程接收到一个信号时内核会更新进程的信号未决位图用于记录当前未被屏蔽的信号。这个位图帮助进程确定是否有信号需要处理。信号挂起位图当一个信号被进程接收但尚未处理时内核会将这个信号标记为挂起即更新进程的信号挂起位图。这个位图帮助进程确定哪些信号需要等待处理。 这三个表是操作系统内核为了管理进程信号处理而设计的数据结构它们在进程创建时被初始化并与进程关联帮助进程识别和处理信号 1.3信号集操作函数 
sigset_t类型 每个信号只有一个bit的未决标志非0即1不记录该信号产生了多少次只表示收到否信号对于信号的数量没办法也没必要阻塞标志也是这样表示的。 因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储sigset_t称为信号集这个类型可以表示每个信号的“有效”或“无效”状态 在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略 对于我们使用者来说应该将sigset_t类型看作一个抽象的信号集合而不需要关心其内部的具体实现细节。sigset_t类型的具体表示方式可能会因系统而异可能是一个位图、一个数组或其他数据结构但这些细节对于使用者来说并不重要。 
我们使用者应该通过系统提供的函数来操作sigset_t变量比如sigemptyset、sigfillset、sigaddset、sigdelset等函数来对信号集进行操作。这些函数会根据系统的具体实现来正确处理信号集的操作确保其正确性和可移植性。 
因此直接打印sigset_t变量是没有意义的因为sigset_t类型的内部表示对于使用者来说是不透明的 
#include signal.h
int sigemptyset(sigset_t* set);
int sigfillset(sigset_t* set);
int sigaddset (sigset_t* set, int signo);
int sigdelset(sigset_t* set, int signo);
int sigismemberconst sigset_t* set, int signo);函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。  函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号。  在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号  sigprocmask系统调用 
sigprocmask是一个系统调用用于检查或修改当前进程的信号屏蔽集signal mask。信号屏蔽集是一个用来指定哪些信号在进程处理信号时应该被阻塞的集合。通过操作信号屏蔽集进程可以控制哪些信号可以被接收和处理哪些信号应该被暂时屏蔽。 
#include signal.h
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);参数说明 
how表示对信号屏蔽集的操作方式有三种取值 SIG_BLOCK将set中指定的信号添加到当前信号屏蔽集中。SIG_UNBLOCK从当前信号屏蔽集中移除set中指定的信号。SIG_SETMASK将当前信号屏蔽集设置为set中指定的信号集。 set指向一个sigset_t类型的指针用于指定要操作的信号集。oldset指向一个sigset_t类型的指针用于存储之前的信号屏蔽集。 
返回值 
如果函数调用成功返回0如果出现错误返回-1并设置errno变量来指示错误类型。 
功能 
sigprocmask函数允许进程检查或修改当前进程的信号屏蔽集。通过how参数指定的操作可以添加、移除或替换信号屏蔽集中的信号。如果oldset参数不为NULL则会将之前的信号屏蔽集存储到oldset中。 
sigpending系统调用 
sigpending是一个系统调用用于获取当前进程挂起/未决pending的信号集。挂起的信号是指已经发送给进程但尚未被处理的信号。通过sigpending函数进程可以查询当前有哪些信号处于挂起状态以便进一步处理这些信号。 
#include signal.h
int sigpending(sigset_t *set);参数说明 
set指向一个sigset_t类型的指针用于存储当前进程挂起的信号集。 
返回值 
如果函数调用成功返回0如果出现错误返回-1并设置errno变量来指示错误类型。 
功能 
sigpending函数允许进程获取当前进程挂起的信号集。通过set参数返回当前进程挂起的信号集可以进一步对这些信号进行处理。 2.信号的处理/递达 
在信号处理中一般情况下有三种处理方式分别是 
忽略信号Ignore进程可以选择忽略某些信号这样当该信号到达时系统不会采取任何操作也不会调用任何信号处理函数。一些信号比如SIGKILL和SIGSTOP是不能被忽略的它们具有特殊的含义和作用。执行默认操作Default Action每个信号都有一个默认的处理方式当进程接收到信号时系统会执行该信号的默认操作。比如当进程接收到SIGINT信号通常由CtrlC触发系统会默认终止进程的执行。捕捉信号并执行处理函数Signal Handling进程可以捕捉信号并注册相应的信号处理函数当接收到信号时系统会调用该处理函数来处理信号。进程可以自定义信号处理函数根据需要对信号进行处理比如记录日志、关闭文件、释放资源等。 
2.1信号处理时机与过程 
我们之前只是泛泛的讲进程会在合适时候进行对信号的处理那什么是合适的时候——进程从内核态切换会用户态的时候信号会被检测并处理 
每次进程从内核态切换到用户态时操作系统会依次检查进程是否有未处理的信号。如果有未处理的信号操作系统会根据信号的处理方式比如忽略、捕获、默认处理等来进行相应的处理。如果信号没有被阻塞操作系统会执行信号处理程序来处理该信号然后继续执行用户态程序。 在第三步我们讨论的是自定义处理如果是默认和忽略呢 默认更改PCB的状态即可观在是内核身份直接杀掉进程忽略处理这个信号什么都不做直接把pending表对应比特位置为0 为什么在第四步里特地回到用户态执行自定义处理函数操作系统不相信任何人不会轻易执行用户的代码因为用户代码可能包含恶意代码或错误代码可能会导致系统崩溃、数据泄露等安全问题 2.2用户态和内核态 
用户态和内核态是操作系统中的两种运行模式用于区分程序的权限和访问级别。下面是它们的主要特点和区别 用户态User Mode 用户态是指程序在执行时所处的一种权限较低的状态程序在用户态下只能访问受限的资源和执行受限的操作。在用户态下程序运行在用户空间只能访问自己的内存空间和受限的系统资源不能直接访问操作系统内核或其他进程的内存空间内核空间。用户态下的程序通常是普通应用程序如文本编辑器、浏览器等它们无法直接执行特权指令或访问系统底层资源。  内核态Kernel Mode 内核态是指程序在执行时所处的一种权限较高的状态程序在内核态下具有更多的权限和访问系统资源的能力。在内核态下程序运行在内核空间可以直接访问系统内核和底层资源执行特权指令和进行敏感操作。内核态下的程序通常是操作系统内核的一部分如设备驱动程序、系统调用处理程序等它们负责管理系统资源、处理中断、执行特权操作等。  我们不同的状态主要是不同的权限通过改变CPU内的执行权限设置了寄存器内的特定标志位来改变状态 2.3再看进程地址空间 进程无论如何切换总能找到OS我们访问OS本质就是通过进程的地址空间的[3,4]GB的内核空间来访问的 调用系统调用也是在地址空间内进行的 在操作系统内核中通常会有一个系统调用表System Call Table用于存储系统调用号与对应系统调用处理程序的映射关系。当用户进程发起系统调用时会将系统调用号放入特定寄存器中CPU根据系统调用号找到对应的系统调用处理程序在系统调用表中的位置然后跳转到该函数的地址进行调用。 在这个过程中操作系统内核会确保系统调用表的起始虚拟地址是已知的并且系统调用号与处理程序的映射关系是正确的。通过这种方式CPU能够根据系统调用号正确地找到对应的系统调用处理程序并执行相应的操作。 谁来运行OS 2.4信号的捕捉—sigaction()函数 当某个信号的处理函数被调用时内核自动将当前信号加入进程的信号屏蔽字。如果我们处理完对应的信号该信号默认也会从信号屏蔽字中进行移除——不想让信号嵌套式进行捕捉处理正在处理时你又来了那就又去调用处理函数 sigaction()函数是用于设置和修改信号处理程序的系统调用函数。通过sigaction()函数进程可以指定在接收到特定信号时应该执行的处理程序。这个处理程序可以是系统默认的处理方式也可以是用户自定义的处理函数。 
sigaction()函数的原型如下 
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);其中signum参数指定了要设置的信号的编号act参数指定了新的信号处理方式oldact参数用于保存之前的信号处理方式。 二者都是struct sigaction类型的对于struct sigaction  void (*sa_handler)(int)这是一个函数指针用于指定信号处理函数的地址。当接收到信号时系统会调用这个函数来处理信号。函数接受一个整型参数表示接收到的信号编号。如果将sa_handler设置为SIG_IGN表示忽略该信号将其设置为SIG_DFL表示使用系统默认的信号处理方式。  void (*sa_sigaction)(int, siginfo_t *, void *)这也是一个函数指针用于指定扩展的信号处理函数的地址。与sa_handler不同的是sa_sigaction函数接受三个参数第一个参数是信号编号第二个参数是一个指向siginfo_t结构体的指针其中包含了关于信号的更多信息第三个参数是一个指向void类型的指针。一般用于实时信号我们不管这个  sigset_t sa_mask这是一个信号集合用于指定在信号处理函数执行期间需要屏蔽的信号。如果有信号在sa_mask指定的信号集合中则这些信号会被阻塞直到信号处理函数执行完毕。  int sa_flags用于指定信号处理的行为。可以是以下几个标志的组合  SA_RESTART表示系统调用在接收到信号后会自动重启。SA_NOCLDSTOP子进程暂停和继续时不会产生SIGCHLD信号。SA_NODEFER不会在执行信号处理函数期间阻止同一信号的传递。SA_SIGINFO表示使用sa_sigaction字段指定的信号处理函数。我们一般设置为0就行了 void (*sa_restorer)(void)这是一个保留字段已经废弃不再使用。 返回值为0表示函数调用成功返回-1表示函数调用失败。在函数调用失败的情况下可以通过errno全局变量获取具体的错误信息。 
通过sigaction()函数进程可以设置信号的处理方式为以下几种之一 
忽略信号SIG_IGN执行默认处理方式SIG_DFL指定自定义的信号处理函数 
#include iostream
#include signal.h
#include unistd.h
using namespace std;void handler(int signum)
{cout  收到了信号  signum  endl;
}int main()
{struct sigaction act, oldact;act.sa_handler  handler;act.sa_flags  0;sigemptyset(act.sa_mask);sigaction(2, act, oldact); // 进行信号捕捉while (true)sleep(2);return 0;
}3.补充知识 
3.1可重入函数 被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数这称为重入函数有可能因为重入而造成错乱像这样的函数称为不可重入函数 反之如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant) 函数 可重入函数Reentrant Function也称为可重入代码Reentrant Code或重入函数Reentrant Routine是指在并发执行环境中能够被多个线程同时调用的函数。这种函数能够在任何时候被中断并在之后从中断点恢复执行而不会导致数据错误或系统崩溃。 
为了实现可重入性可重入函数必须满足以下条件 
不使用静态全局非常量数据静态或全局非常量数据可能在多个线程之间共享如果一个线程修改了这些数据其他线程可能无法正确地读取或写入这些数据导致数据错误。不调用不可重入函数如果一个函数调用了另一个不可重入的函数那么它本身也将是不可重入的。不返回指向静态全局非常量数据的指针与第一条类似返回这样的指针可能导致其他线程错误地修改或读取数据。使用局部变量局部变量存储在函数的栈帧中每个函数调用都有自己的栈帧因此局部变量是线程私有的不会被其他线程干扰。对共享资源的访问进行保护如果函数需要访问共享资源如文件、数据库、共享内存等则需要使用适当的同步机制如互斥锁、信号量等来保护这些资源防止数据竞争和冲突。 
3.2volatile关键字 volatile 关键字在 C 和 C 语言中是一个类型限定符它告诉编译器不要对访问该关键字声明的变量的代码进行优化即每次都需要从内存中读取变量的值而不是使用存储在寄存器中的副本。这是为了确保多线程环境或者硬件中断等场景下对该变量的访问总是最新的、未被其他线程或硬件修改过的值。 有时因为编译器优化的原因会导致我们代码出错 #include stdio.h
#include unistd.h
#include signal.hint g_flag  0;void changeflag(int signo)
{(void)signo;printf(将g_flag,从%d-%d\n, g_flag, 1);g_flag  1;
}int main()
{signal(2, changeflag);while(!g_flag); // 故意写成这个样子, 编译器默认会对我们的代码进行优化//因为g_flag一直都没使用过printf(process quit normal\n);return 0;
}这里如果编译器进行优化会把内存里的g_flag拷贝一份到寄存器里那下一次判断直接从寄存器里拿。不用再去内存里拿收到信号2后我们更改的是内存里的g_flag但是我们while判断的是寄存器里的g_flag——寄存器屏蔽了内存 3.3 SIGCHLD信号 
SIGCHLD信号是在Linux系统中用于进程间通信的一种机制。具体来说当子进程终止或停止时子进程会向其父进程发送SIGCHLD信号。这个信号是子进程状态改变时发送给父进程的信号用于通知父进程其子进程的状态已经发生了变化。 
父进程可以捕获这个信号并通过调用如wait()或waitpid()等函数来获取子进程的退出状态、终止原因等信息。SIGCHLD信号常用于以下几种情况 
子进程终止父进程需要回收子进程的资源。父进程需要等待子进程的状态改变比如子进程终止或停止。父进程需要在子进程终止后进行一些操作。 
在处理SIGCHLD信号时通常会在信号处理函数中循环调用waitpid()函数来非阻塞等待子进程状态改变以避免僵尸进程的产生。 有可能有100个子进程有50个退出了50个还没有。那么在循环到51次时waitpid会一直堵塞住父进程就一直卡在那里所以不能堵塞等待 #include iostream
#include unistd.h
#include signal.h
#include sys/types.h
#include sys/wait.hvoid CleanupChild(int signum)
{while (true){pid_t rid  waitpid(-1, nullptr, WNOHANG); // -1 : 回收任意一个子进程这里非堵塞if (rid  0)//等待成功{std::cout  wait child success:   rid  std::endl;}else if (rid  0)break;}
}int main()
{signal(SIGCHLD, CleanupChild);for (int i  0; i  100; i){pid_t id  fork();if (id  0){// childint cnt  5;while (cnt--){std::cout  I am child process:   getpid()  std::endl;sleep(1);}std::cout  child process died  std::endl;exit(0);}}// fatherwhile (true)sleep(1);return 0;
}事实上,由于UNIX的历史原因要想不产生僵尸进程还有另外一种办法:父进程调 用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉不会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略 通常是没有区别的,但这是一个特例。此方法对于Linux可用 signal(SIGCHLD, SIG_IGN);//直接这样就行好了今天就到这里啦 文章转载自: http://www.morning.lxyyp.cn.gov.cn.lxyyp.cn http://www.morning.mfrb.cn.gov.cn.mfrb.cn http://www.morning.jtwck.cn.gov.cn.jtwck.cn http://www.morning.qmxsx.cn.gov.cn.qmxsx.cn http://www.morning.kzhgy.cn.gov.cn.kzhgy.cn http://www.morning.fldsb.cn.gov.cn.fldsb.cn http://www.morning.hctgn.cn.gov.cn.hctgn.cn http://www.morning.tkfnp.cn.gov.cn.tkfnp.cn http://www.morning.rybr.cn.gov.cn.rybr.cn http://www.morning.mrxgm.cn.gov.cn.mrxgm.cn http://www.morning.tnjff.cn.gov.cn.tnjff.cn http://www.morning.yrnll.cn.gov.cn.yrnll.cn http://www.morning.nqmhf.cn.gov.cn.nqmhf.cn http://www.morning.ksgjn.cn.gov.cn.ksgjn.cn http://www.morning.rzscb.cn.gov.cn.rzscb.cn http://www.morning.ryrpq.cn.gov.cn.ryrpq.cn http://www.morning.mmclj.cn.gov.cn.mmclj.cn http://www.morning.klyyd.cn.gov.cn.klyyd.cn http://www.morning.rqfnl.cn.gov.cn.rqfnl.cn http://www.morning.hhqtq.cn.gov.cn.hhqtq.cn http://www.morning.rgmd.cn.gov.cn.rgmd.cn http://www.morning.lxjcr.cn.gov.cn.lxjcr.cn http://www.morning.jbfjp.cn.gov.cn.jbfjp.cn http://www.morning.wlbwp.cn.gov.cn.wlbwp.cn http://www.morning.pbtdr.cn.gov.cn.pbtdr.cn http://www.morning.qcwck.cn.gov.cn.qcwck.cn http://www.morning.mllmm.cn.gov.cn.mllmm.cn http://www.morning.tdhxp.cn.gov.cn.tdhxp.cn http://www.morning.hxxyp.cn.gov.cn.hxxyp.cn http://www.morning.gydsg.cn.gov.cn.gydsg.cn http://www.morning.fhrgk.cn.gov.cn.fhrgk.cn http://www.morning.yrjkp.cn.gov.cn.yrjkp.cn http://www.morning.leboju.com.gov.cn.leboju.com http://www.morning.jkdtz.cn.gov.cn.jkdtz.cn http://www.morning.bpmtg.cn.gov.cn.bpmtg.cn http://www.morning.cwnqd.cn.gov.cn.cwnqd.cn http://www.morning.nlkm.cn.gov.cn.nlkm.cn http://www.morning.pqwhk.cn.gov.cn.pqwhk.cn http://www.morning.fkrzx.cn.gov.cn.fkrzx.cn http://www.morning.wtlyr.cn.gov.cn.wtlyr.cn http://www.morning.yxbdl.cn.gov.cn.yxbdl.cn http://www.morning.ddxjr.cn.gov.cn.ddxjr.cn http://www.morning.ccphj.cn.gov.cn.ccphj.cn http://www.morning.ybnzn.cn.gov.cn.ybnzn.cn http://www.morning.qkxt.cn.gov.cn.qkxt.cn http://www.morning.nafdmx.cn.gov.cn.nafdmx.cn http://www.morning.qdbcd.cn.gov.cn.qdbcd.cn http://www.morning.rqknq.cn.gov.cn.rqknq.cn http://www.morning.gfrtg.com.gov.cn.gfrtg.com http://www.morning.nnpwg.cn.gov.cn.nnpwg.cn http://www.morning.fbqr.cn.gov.cn.fbqr.cn http://www.morning.qnbzs.cn.gov.cn.qnbzs.cn http://www.morning.bbgn.cn.gov.cn.bbgn.cn http://www.morning.rlkgc.cn.gov.cn.rlkgc.cn http://www.morning.hhrpy.cn.gov.cn.hhrpy.cn http://www.morning.kgfsz.cn.gov.cn.kgfsz.cn http://www.morning.nkbfc.cn.gov.cn.nkbfc.cn http://www.morning.jqwpw.cn.gov.cn.jqwpw.cn http://www.morning.psxwc.cn.gov.cn.psxwc.cn http://www.morning.lxjcr.cn.gov.cn.lxjcr.cn http://www.morning.rkck.cn.gov.cn.rkck.cn http://www.morning.hmdyl.cn.gov.cn.hmdyl.cn http://www.morning.jlmrx.cn.gov.cn.jlmrx.cn http://www.morning.jgcxh.cn.gov.cn.jgcxh.cn http://www.morning.bzfld.cn.gov.cn.bzfld.cn http://www.morning.rrcrs.cn.gov.cn.rrcrs.cn http://www.morning.xfmwk.cn.gov.cn.xfmwk.cn http://www.morning.qinhuangdjy.cn.gov.cn.qinhuangdjy.cn http://www.morning.ljtwp.cn.gov.cn.ljtwp.cn http://www.morning.gyzfp.cn.gov.cn.gyzfp.cn http://www.morning.gyfhk.cn.gov.cn.gyfhk.cn http://www.morning.hkpyp.cn.gov.cn.hkpyp.cn http://www.morning.fdxhk.cn.gov.cn.fdxhk.cn http://www.morning.gpryk.cn.gov.cn.gpryk.cn http://www.morning.lcbgf.cn.gov.cn.lcbgf.cn http://www.morning.ksqzd.cn.gov.cn.ksqzd.cn http://www.morning.ctpfq.cn.gov.cn.ctpfq.cn http://www.morning.gwdkg.cn.gov.cn.gwdkg.cn http://www.morning.mmxt.cn.gov.cn.mmxt.cn http://www.morning.xnkh.cn.gov.cn.xnkh.cn