当前位置: 首页 > news >正文

建设厅安检局网站给 wordpress category (分类)添加字段

建设厅安检局网站,给 wordpress category (分类)添加字段,wordpress博客文章美化,网络营销方式对比分析论文目录 一、Linux中的信号 1、Linux中的信号 2、进程对信号的处理 3、信号的释义 二、信号的捕捉 1、信号的捕捉signal() 2、信号的捕捉sigaction() 三、信号如何产生#xff1f; 1、kill()用户调用kill向操作系统发送信号 通过命令行参数模仿写一个kill命令 2、rais… 目录 一、Linux中的信号 1、Linux中的信号 2、进程对信号的处理 3、信号的释义 二、信号的捕捉 1、信号的捕捉signal() 2、信号的捕捉sigaction() 三、信号如何产生 1、kill()用户调用kill向操作系统发送信号 通过命令行参数模仿写一个kill命令 2、raise()进程自己给自己发任意信号实际上是操作系统-进程 3、abort()进程自己给自己发6号信号 4、硬件异常产生信号 4.1八号信号SIGFPE除零错误可引发 4.2十一号信号SIGSEGV段错误可引发 5、软件条件产生异常 5.1十三号信号SIGPIPE匿名管道读端关闭写端收到该信号 5.2十四号信号SIGALRM定时器 6、信号相关问答 四、进程退出时的核心转储 1、核心转储的定义 2、核心转储的意义 五、信号的保存位图结构 1、相关概念铺垫 2、信号在内核中的表示 六、信号的处理 1、再谈进程地址空间 1.1用户态-内核态 1.2进程如何从用户态切换至内核态并执行内核代码 2、信号的捕捉流程 3、sigset_t信号集调库用于处理block和pending位图中的01 4、sigprocmask调用该函数可读取或更改阻塞信号集 5、sigpending获取当前进程的pending信号集 6、屏蔽信号并实时打印pending位图运用上方三个接口 七、可重入函数 八、volatile关键字 九、SIGCHLD信号 一、Linux中的信号 1、Linux中的信号 使用kill -l查看所有信号。使用信号时可使用信号编号或它的宏。 1、Linux中信号共有61个没有0、32、33号信号。 2、【1,31】号信号称为普通信号【34,64】号信号称为实时信号。 以普通信号为例进程task_struct结构体中存在unsigned int signal变量用以存放普通信号。32个比特位中使用0/1存储、区分31个信号——位图结构 那么发送信号就是修改进程task_struct结构体中的信号位图。当然有权限改动进程PCB的也只有操作系统了。 2、进程对信号的处理 1、进程本身是程序员编写的属性和逻辑的集合 2、信号可以随时产生异步。但是进程当前可能正在处理更为重要的事情当信号到来时进程不一定会马上处理这个信号 3、所以进程自身必须要有对信号的保存能力 4、进程在处理信号时信号被捕捉一般有三种动作默认、自定义、忽略。 3、信号的释义 man 7 signal查看信号详细信息的命令 Trem正常结束Core异常退出可以使用核心转储功能定位错误见本文第四节Ign内核级忽略。 2SIGINT 终止信号即键盘输入ctrlc 3SIGQUIT 终止信号即键盘输入ctrl\ 6SIGABRT 终止信号 调用abort即可收到该信号 8SIGFPE 终止信号 除0错误即可收到该信号 11SIGSEGV 终止信号 段错误即可收到该信号 13SIGPIPE 终止信号 匿名管道读端关闭写端即可收到该信号 14SIGALRM 终止信号 alarm()函数定时器 17SIGCHLD 内核级忽略信号 子进程退出时会向父进程发送该信号 18SIGURG 继续进程进程切换至后台运行通过9号信号杀掉 19SIGSTOP 暂停进程 可以发现有挺多信号的功能都是一样的。这是因为不同的信号可以代表发生了不同的事件但处理结果可以一致。 二、信号的捕捉 1、信号的捕捉signal() SIGNAL(2) #include signal.h typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);//signum被捕捉的信号编号handler对指定的信号设置自定义动作 handler设置为SIG_DFL表示信号默认处理方式,SIG_ING设置为忽略处理 #include iostream #include unistd.h #include signal.h void hancler(int signo) {//这里写自定义内容捕获到signo信号后即可执行自定义代码std::cout进程捕捉到信号signostd::endl; } int main() {signal(2,hancler);//外部需要对该进程发送信号while(1){std::coutgetpid()std::endl;sleep(1);}return 0; } 外部需要对该进程发送信号才能被signal接口捕捉。上面例子中外部发送kill -2 PID或者键盘ctrlc都行。 当捕捉到指定信号后将会执行自定义函数。可用于信号功能的替换。 9号和19号信号无法被捕捉。kill -9乱杀进程kill -19暂停进程。 2、信号的捕捉sigaction() SIGACTION(2) #include signal.h int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact); signum信号act结构体对象oldact输出型参数记录原来的act对象 struct sigaction {void (*sa_handler)(int);//回调方法void (*sa_sigaction)(int, siginfo_t *, void *);sigset_t sa_mask;//阻塞信号集int sa_flags;void (*sa_restorer)(void);//用于支持旧版本的sigaction函数的信号处理函数地址一般不使用。 }; Sigaction()在成功时返回0; 在错误时返回 -1并设置 errno。 当一个信号正在被递达执行期间pending位图由1置0同时该信号将被阻塞。 如果这时再接收到这个信号发现该信号被阻塞同时pending位图由0置1保存这个信号。 若同一时间再接收到该信号由于pending已存满多余的该信号将被丢失。 当首个信号被捕捉完毕操作系统会立即解除对该信号的屏蔽因为pending位图对应的比特位是1所以立即执行新的捕捉动作同时pending位图该信号位由1清零。 这就是上图执行结果出现两次2号信号捕捉的原因。 三、信号如何产生 1、kill()用户调用kill向操作系统发送信号 通过命令行参数模仿写一个kill命令 有一个系统调用kill用户使用kill函数让操作系统向进程发送信号。 KILL(2) #include sys/types.h #include signal.h int kill(pid_t pid, int sig);//pid目标进程的pid。sig几号信号 成功时(至少发送了一个信号) 返回零。出现错误时返回 -1设置errno mysignal.cc #include iostream #include cstdio #include unistd.h #include sys/types.h #include signal.h #include string void Usage(const std::string proc) {std::coutUsige:getpid() Signno\nstd::endl; }int main(int argc,char* argv[])//运行main函数时需要先进行传参 {if(argc!3)//如果传入main函数的参数个数不为3{Usage(argv[0]);exit(1);}pid_t pidatoi(argv[1]);//获取第一个命令行参数,作为pidint signoatoi(argv[2]);//获取第二个命令行参数,作为signoint nkill(pid,signo);//需要发送信号的进程/发送几号信号if(n-1)//kill()失败返回-1{perror(kill);}while(1){std::coutgetpid()std::endl;sleep(1);}return 0; } 2、test.cc #include iostream #include unistd.h #include sys/types.h int main() {while(1){std::cout这是一个正在运行的进程getpid()std::endl;sleep(1);}return 0; } 2、raise()进程自己给自己发任意信号实际上是操作系统-进程 RAISE(3) #include signal.h int raise(int sig);//sig信号编号 raise()在成功时返回0在失败时返回非0。 raise(signo)等于kill(getpid,signo); //当计数器运行到5时进程会因3号进程退出 int main(int argc,char* argv[])//运行main函数时需要先进行传参 {int cnt0;while(cnt10){std::coutcntstd::endl;sleep(1);if(cnt5){raise(3);}}return 0; } 3、abort()进程自己给自己发6号信号 ABORT(3) #include stdlib.h void abort(void); 函数 abort()永远不会返回 abort()等于kill(getpid,SIGABRT); 4、硬件异常产生信号 硬件异常指非人为调用系统接口等行为因软件问题造成的硬件发生异常。操作系统通过获知对应硬件的状态即可向对应进程发送指定信号。 4.1八号信号SIGFPE除零错误可引发 例如出现除0错误操作系统将会发送8号信号SIGFPE。 此时使用signal()捕捉这个信号就会发现8号信号一直在被捕捉。这是因为状态寄存器是由CPU进行维护的当8号信号被捕捉进程并没有退出根据时间片轮转当进程被切换/剥离至CPU时会读取和保存当前寄存器的上下文信息所以我们就看到了8号信号被死循环捕捉。 4.2十一号信号SIGSEGV段错误可引发 5、软件条件产生异常 5.1十三号信号SIGPIPE匿名管道读端关闭写端收到该信号 例如匿名管道读端关闭操作系统会向写端发送13号信号SIGPIPE终止写端。 5.2十四号信号SIGALRM定时器 设置alarm函数是在告诉操作系统将在设定的时间到来时向进程发送14号信号终止进程。 ALARM(2) #include unistd.h unsigned int alarm(unsigned int seconds);//seconds延时几秒 返回值为定时器剩余的秒数可能会被提前唤醒 alarm(0)表示取消之前设定的闹钟 //设置一个cnt用于测试代码在指定时间跑了多少 void hancler(int signo) {//这里写自定义内容捕获到signo信号后即可执行自定义代码std::cout进程捕捉到信号signo cntstd::endl;//检测到5秒后cnt为多少alarm(5);//循环捕捉闹钟 } int main() {signal(14,hancler);alarm(1);//定时1秒alarm(5);//定义新的闹钟旧闹钟会失效哦while(1){cnt;}return 0; } 闹钟是由软件实现的。任何一个进程都可以通过alarm函数设定闹钟所以操作系统需要通过先描述再组织的方式管理这些闹钟。 6、信号相关问答 所有信号产生最终都要有操作系统来进行执行因为操作系统是进程的管理者 。 信号的处理是否是立即处理的见下文~ 信号如果没有被立即处理那么信号将被保存至pending位图中 一个进程在没有收到信号的时候能否知道自己应该对合法信号作何处理呢 能程序员写好了对应信号的处理方式你没走人行道但你知道红灯停绿灯行 如何理解OS向进程发送信号能否描述一下完整的发送处理过程操作系统直接修改进程pcb中的信号位图。 四、进程退出时的核心转储 信号旁边写着Core的信号都可以使用核心转储功能。 1、核心转储的定义 核心转储:当进程出现异常时将进程在对应时刻的有效数据由内存存储至磁盘。 云服务器默认关闭了核心转储。在终端输入ulimit -a显示操作系统各项资源上限使用ulimit -c 1000允许操作系统最大设置1000个block大小的数据块。 2、核心转储的意义 将程序异常的原因转储至磁盘支持后续调试。 五、信号的保存位图结构 1、相关概念铺垫 1、信号递达(Delivery) 实际执行信号的处理动作 2、信号未决(Pending)信号从产生到递达之间的状态 3、进程可以选择阻塞 (Block )某个信号。 4、信号被阻塞时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作. 5、阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。 2、信号在内核中的表示 例如signal捕获信号的流程就是通过signo编号修改handler[signo]中的函数指针指向用户自定义的信号处理方法。当收到信号时将pending位图中对应的比特位修改为1若block位图中没有阻塞该信号该信号被递达时就会执行该信号的处理方法。 对于普通信号pending位图同时间只能保存一次同个信号若该信号处于未递达状态后续再次收到该信号将无法被保存丢失。 六、信号的处理 1、再谈进程地址空间 博主首篇进程地址空间传送门【Linux】进程地址空间 1.1用户态-内核态 1.2进程如何从用户态切换至内核态并执行内核代码 每个进程的虚拟地址空间中有一块1G大小的内核空间通过内核级页表映射的方式找到物理内存中内核代码进行执行。 由于内核级页表中对应物理地址的映射关系是一样的所以每个进程都可以使用相同的内核级页表无论进程如何切换均可使用同一张内核级页表进行映射调用。 在进行用户态-内核态的切换过程中首先通过CR3寄存器将进程状态由用户态修改为内核态陷入内核在本进程的内核空间中找到物理内存中的内核代码进行执行执行完毕后将结果返回给进程。 2、信号的捕捉流程 信号的自定义捕捉信号在产生的时候不会被立刻处理而是从内核态返回用户态的时候对信号进行处理。 进程首先因为中断、异常、系统调用陷入内核以内核态的身份运行内核代码通过进程控制块中的信号位图分析当前信号的处理方式。 若为自定义处理则需要进程回到用户态去执行用户设定的handler方法。为什么进程不能以内核态的身份直接执行handler方法这是因为进程处于内核态权限非常高操作系统是没有能力识别代码的逻辑的若handler被人为植入恶意代码原先部分没有权限的代码因为执行身份的变化而被提权所以操作系统必须让进程先回到用户态降低进程的权限。 执行完handler方法后进程需要重新回到内核态去执行一些系统调用才能回退回用户态。 3、sigset_t信号集调库用于处理block和pending位图中的01 每个信号只有一个bit的未决/阻塞标志,非0即1,不记录该信号产生了多少次。 因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集。这个类型可以表示每个信号的“有效”或“无效”状态。 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。 #include signal.h 函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号。 int sigemptyset(sigset_t *set); 函数sigfifillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号。 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); 在使用sigset_ t类型的变量之前,一定要调用sigemptyset或sigfifillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。 这四个函数都是成功返回0,出错返回-1。sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。 4、sigprocmask调用该函数可读取或更改阻塞信号集 #include signal.h int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 返回值:若成功则为0,若出错则为-1 如果oset是非空指针,则读取进程的当前信号屏蔽字并通过oset参数传出。 如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。 如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。 how如何屏蔽信号集 SIG_BLOCK set包含了我们希望添加到当前信号屏蔽字的信号相当于maskmask | set SIG_UNBLOCK set包含了我们希望从当前信号屏蔽字解除阻塞的信号相当于maskmask~set SIG_SETMASK 设置当前信号屏蔽字为set所指向的值相当于maskset 如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。没有手动捕捉的话一般信号都是终止的所以递达了进程大概率也就寄了。 5、sigpending获取当前进程的pending信号集 SIGPENDING(2) #include signal.h int sigpending(sigset_t *set);//set输出型参数输出当前进程pending位图 sigending()在成功时返回0在错误时返回-1。在发生错误时将 errno 设置。 6、屏蔽信号并实时打印pending位图运用上方三个接口 默认情况所有的信号是不被阻塞的如果一个信号被屏蔽了那么这个信号不会被递达。 #include iostream #include vector #include signal.h #include unistd.h// #define BLOCK_SIGNAL 2 #define MAX_SIGNUM 31using namespace std;// static vectorint sigarr {2,3}; static vectorint sigarr {2};static void show_pending(const sigset_t pending) {for(int signo MAX_SIGNUM; signo 1; signo--){if(sigismember(pending, signo)){cout 1;}else cout 0;}cout \n; }static void myhandler(int signo) {cout signo 号信号已经被递达!! endl; }int main() {for(const auto sig : sigarr) signal(sig, myhandler);// 1. 先尝试屏蔽指定的信号sigset_t block, oblock, pending;// 1.1 初始化sigemptyset(block);sigemptyset(oblock);sigemptyset(pending);// 1.2 添加要屏蔽的信号for(const auto sig : sigarr) sigaddset(block, sig);// 1.3 开始屏蔽,设置进内核(进程)sigprocmask(SIG_SETMASK, block, oblock);// 2. 遍历打印pengding信号集int cnt 10;while(true){// 2.1 初始化sigemptyset(pending);// 2.2 获取它sigpending(pending);// 2.3 打印它show_pending(pending);// 3. 慢一点sleep(1);if(cnt-- 0){sigprocmask(SIG_SETMASK, oblock, block); // 一旦对特定信号进行解除屏蔽一般OS要至少立马递达一个信号cout 恢复对信号的屏蔽不屏蔽任何信号\n;}} } 七、可重入函数 main函数调用insert函数向一个链表head中插入节点P1,插入操作分为两步,刚执行完第一句代码,此时硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作执行完毕后sighandler返回内核态,再次回到用户态就从main函数继续执行刚才剩余的代码。结果是,main函数和sighandler先后向链表中插入两个节点,而最后只有P1真正插入链表中P2这个节点谁都找不到了。发生内存泄漏。 像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱。像这样的函数称为不可重入函数,反之, 如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant) 函数。 不可重入函数调用了malloc或free,因为malloc也是用全局链表来管理堆的。 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。 八、volatile关键字 优化后通过信号自定义方法handler修改全局q,但是程序不会退出。 O3优化时编译器认为q在main执行流中没有被修改所以编译器对q做了优化直接将q放在了寄存器中这样后续执行时就不用再去内存中读取q了提高了程序运行效率。虽然handler中修改了内存中的q但是寄存器中的q值一直是1寄存器中的q值是临时值操作系统没有对其进行修改所以会发生上图效果。 解决方法给q加volatile关键字让q通过内存读取而不是寄存器保持变量q的内存可见性。 #include iostream #include unistd.h #include signal.h #include sys/types.h volatile int q1;//保持内存可见性 void handler(int signo) {q0; } int main() {signal(2,handler);while(q!0);return 0; } 当程序结果与预期偏离时可以尝试使用volatile关键字万一就是编译器过度优化造成的程序逻辑异常呢 九、SIGCHLD信号 1、子进程退出会向父进程发送17号信号SIGCHLD 2、由于UNIX 的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调 用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。 //忽略子进程发出的17号信号 signal(SIGCHLD,SIG_IGN); sigaction(SIGCHLD,act,oldact);//act中忽略17号信号 系统默认的忽略动作和用户用signal/sigaction函数自定义的忽略 通常是没有区别的,但这里是一个特例。 虽然信号SIGCHID的默认动作也是忽略但这个忽略是实实在在的无视了这个信号我们手动在handler方法中使用SIG_IGN子进程退出时发送给父进程的信号将会被父进程忽略但子进程会被操作系统回收这就是区别所在。
http://www.dnsts.com.cn/news/84986.html

相关文章:

  • 顺义做网站的厂家wordpress迅雷插件下载
  • 安徽工业大学两学一做网站工作细胞第一季免费
  • 模板手机网站建设价格明细表做二手网站有哪些问题
  • 摄影网站模板下载企业信用不良记录查询
  • 做PS的赚钱的网站在线crm客户关系管理
  • 商品网站建设实验格式中国建设网建设通
  • 做义齿雕刻设备的网站2023还能上的网站
  • 阜南做网站公司网站制作验收单
  • 辽宁省建设机械协会官方网站成品网站的安装教程
  • 网站开发公司上在中国做国外网站
  • 嘉兴网站设计999 999最新网站开发软件
  • 怎么建设网站容易被百度抓取googl浏览器做桌面版网站
  • 如何做好一个外贸网站的编辑网站开发留学
  • 重庆多功能网站建设thinkphp 网站根目录地址
  • 厦门网站推广¥做下拉去118cr济南网站优化哪里做的好
  • 中间商可以做网站吗指数基金是什么意思
  • 学做网站知识大理企业网站建设
  • 桂林本地网站电子商务网站建设与管理相关论文
  • asp网站怎么打开网站设计与制作的过程
  • 绍兴建设局网站首页怎么把凡科网里做的网站保存成文件
  • 在线搭建网站建设热电偶网站
  • wordpress网站第一次打开慢wordpress 客户
  • 制作做的网站如何上传网上德州网站建设价格
  • 网站建站推荐潍坊专业联轴器收购价格
  • 做个中英文网站多少钱wordpress自动同步
  • 微服务网站开发小程序怎么开
  • 网站做优化需要多少钱便宜网站建设模板网站
  • 怎样做 网站做seo荆州网站seo
  • 58做网站一年多少钱免费自助设计网站
  • 最大的房产网站排名建立网站的技术