Webserver(2.6)信号

news/2024/11/2 14:52:43/

目录

  • 信号的概念
  • 信号相关的函数
    • kill
    • raise
    • abort
    • alarm
      • 1s钟电脑能数多少个数?
    • setitimer
      • 过3s以后,每隔2s定时一次
  • 信号捕捉函数
    • signal
    • sigaction
  • 信号集
    • sigprocmask
      • 编写一个程序,把所有的常规信号未决状态打印到屏幕
  • sigchld信号

信号的概念

比如ctrl+c会进程发送一个中断信号
硬件发生异常,比如被0除,野地址
系统状态变化,alarm定时器、超过cpu时间片,子进程退出
kill命令

信号相关的函数

kill

给某个进程pid发送某个信号sig

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>int main(){pid_t pid=fork();if(pid==0){//子进程for(int i=0;i<5;i++){printf("child process\n");sleep(1);}}else if(pid>0){//父进程printf("parent process\n");sleep(2);printf("kill child process now\n");kill(pid,SIGINT);}return 0;
}

在这里插入图片描述

raise

给当前进程发送信号(kill可以给任何进程)

abort

alarm

设置定时器
开始倒计时,当倒计时为0时终止当前进程
每一个进程只有唯一的一个定时器,如果第二次出现alarm(重新倒计时),返回值是上一个剩余的时间
该函数不阻塞

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>int main(){int secondes=alarm(5);printf("seconds:%d\n",secondes);sleep(2);secondes=alarm(10);printf("seconds:%d\n",secondes);while(1){}return 0;
}

在这里插入图片描述

1s钟电脑能数多少个数?

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>int main(){alarm(1);int i=0;while(1){printf("%i\n",i++);}return 0;
}

在这里插入图片描述
实际上更多,因为在这边写到终端上i/o缓冲也占了时间,就是没全部打印出来,就已经显示闹钟了
在这里插入图片描述
有五百万次
在这里插入图片描述
实际的时间=内核时间+用户时间+消耗的时间
进行文件IO操作的时候比较浪费时间

alarm是自然计时,不受sleep的影响

setitimer

设置定时器,且精度更高,到微秒
每个阶段发送信号

过3s以后,每隔2s定时一次

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>int main(){struct itimerval new_value;//设置间隔的时间new_value.it_interval.tv_sec=2;new_value.it_interval.tv_usec=0;//设置延迟的时间,3s之后开始第一次定时new_value.it_value.tv_sec=3;new_value.it_value.tv_usec=0;int ret=setitimer(ITIMER_REAL,&new_value,NULL);printf("定时器开始了...\n");if(ret==-1){perror("setitimer");exit(0);}getchar();return 0;
}

信号捕捉函数

signal

sigkill(9号信号) sigstop不能被捕捉,不能被忽略

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>int main(){//注册信号捕捉signal(SIGALRM,SIG_IGN);struct itimerval new_value;//设置间隔的时间new_value.it_interval.tv_sec=2;new_value.it_interval.tv_usec=0;//设置延迟的时间,3s之后开始第一次定时new_value.it_value.tv_sec=3;new_value.it_value.tv_usec=0;int ret=setitimer(ITIMER_REAL,&new_value,NULL);printf("定时器开始了...\n");if(ret==-1){perror("setitimer");exit(0);}getchar();return 0;
}

捕捉到信号之后,信号忽略,原先终止,现在啥都不做
在这里插入图片描述

signal(SIGALRM,SIG_DFL);

换成默认,默认就是终止进程,倒计时结束就结束
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

sigaction

SIGKILL和SIGSTOP不能被忽略也不能被捕捉

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>void myalarm(int num){printf("捕捉到了信号的编号是:%d\n",num);printf("xxxx\n");
}int main(){struct sigaction act;act.sa_flags=0;act.sa_handler=myalarm;sigemptyset(&act.sa_mask);//清空零时阻塞信号集//注册信号捕捉sigaction(SIGALRM,&act,NULL);struct itimerval new_value;//设置间隔的时间new_value.it_interval.tv_sec=2;new_value.it_interval.tv_usec=0;//设置延迟的时间,3s之后开始第一次定时new_value.it_value.tv_sec=3;new_value.it_value.tv_usec=0;int ret=setitimer(ITIMER_REAL,&new_value,NULL);printf("定时器开始了...\n");if(ret==-1){perror("setitimer");exit(0);}while(1);return 0;
}

每两秒捕捉一次定时器的alarm信号,然后调用回调函数
在这里插入图片描述

信号集

#include<signal.h>
#include<stdio.h>int main(){//创建一个信号集sigset_t set;//清空信号集的内容sigemptyset(&set);//判断sigint是否在信号集set里int ret=sigismember(&set,SIGINT);if(ret==0){printf("SIGINT 不阻塞\n");}else if(ret==1){printf("SIGINT 阻塞\n");}//添加几个信号到信号集中sigaddset(&set,SIGINT);sigaddset(&set,SIGQUIT);//判断sigint是否在信号集set里ret=sigismember(&set,SIGINT);if(ret==0){printf("SIGINT 不阻塞\n");}else if(ret==1){printf("SIGINT 阻塞\n");}//判断sigquit是否在信号集set里ret=sigismember(&set,SIGQUIT);if(ret==0){printf("SIGQUIT 不阻塞\n");}else if(ret==1){printf("SIGQUIT 阻塞\n");}//从信号集中删除一个信号sigdelset(&set,SIGQUIT);//判断sigquit是否在信号集set里ret=sigismember(&set,SIGQUIT);if(ret==0){printf("SIGQUIT 不阻塞\n");}else if(ret==1){printf("SIGQUIT 阻塞\n");}return 0;
}

在这里插入图片描述

sigprocmask

对内核的信号集进行操作

编写一个程序,把所有的常规信号未决状态打印到屏幕

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>int main(){//设置2号、3号信号阻塞sigset_t set;sigemptyset(&set);//将2号和3号信号添加到信号集中sigaddset(&set,SIGINT);sigaddset(&set,SIGQUIT);//修改内核中的阻塞信号sigprocmask(SIG_BLOCK,&set,NULL);while(1){//获取当前的未决信号集的数据sigset_t pendingset;sigemptyset(&pendingset);sigpending(&pendingset);//遍历前32位for(int i=1;i<=32;i++){if(sigismember(&pendingset,i)==1){printf("1");}else if(sigismember(&pendingset,i)==0){printf("0");}else{perror("sigismember");exit(0);}}printf("\n");}return 0;
}

在这里插入图片描述
在这里插入图片描述

未决信号集和阻塞信号集

sigchld信号

子进程终止时,产生
子进程接收到SIGSTOP信号(暂停进程,不是停止)
子进程处于停止态(暂停),接受到SIGCONT唤醒时

以上三种情况,内核会发送SIGCHLD信号给父进程,父进程默认忽略该信号。
用于解决僵尸进程问题,不需要父进程来wait,子进程结束之后发送信号。
然后父进程捕捉该信号,再去调用pid来wait回收资源,之后父进程继续做自己的事情。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include<sys/stat.h>int main(){//创建一些子进程pid_t pid;for(int i=0;i<20;i++){pid=fork();if(pid==0){break;}}if(pid>0){//父进程while(1){printf("parent process pid:%d\n",getpid());sleep(2);}}else if(pid==0){//子进程printf("child process pid:%d\n",getpid());}return 0;
}

创建20个子进程,产生了僵尸进程
在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include<sys/stat.h>
#include <signal.h>void myFun(int num){printf("捕捉到的信号:%d\n",num);
}int main(){//创建一些子进程pid_t pid;for(int i=0;i<20;i++){pid=fork();if(pid==0){break;}}if(pid>0){//父进程//捕捉子进程死亡时发送的sigchld信号struct sigaction act;act.sa_flags=0;act.sa_handler=myFun;sigemptyset(&act.sa_mask);sigaction(SIGCHLD,&act,NULL);while(1){printf("parent process pid:%d\n",getpid());sleep(2);}}else if(pid==0){//子进程printf("child process pid:%d\n",getpid());}return 0;
}

子进程死了之后,就捕捉到了17号信号(SIGCHLD)
在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include<sys/stat.h>
#include <signal.h>
#include<sys/wait.h>void myFun(int num){printf("捕捉到的信号:%d\n",num);//回收子进程PCB的资源while(1){int ret=waitpid(-1,NULL,WNOHANG);if(ret>0){printf("child die,pid=%d\n",ret);}else if(ret==0){//说明还有子进程活着break;}else if(ret==-1){//所有子进程结束了break;}}}int main(){//创建一些子进程pid_t pid;for(int i=0;i<20;i++){pid=fork();if(pid==0){break;}}if(pid>0){//父进程//捕捉子进程死亡时发送的sigchld信号struct sigaction act;act.sa_flags=0;act.sa_handler=myFun;sigemptyset(&act.sa_mask);sigaction(SIGCHLD,&act,NULL);while(1){printf("parent process pid:%d\n",getpid());sleep(2);}}else if(pid==0){//子进程printf("child process pid:%d\n",getpid());}return 0;
}

全部被捕捉并处理,没有僵尸进程
在这里插入图片描述
还有个问题就是,如果在捕捉信号注册还没完成的时候,子进程就已经全部结束了,那这个时候就不会再发生sigchld了,那就不会被回收了。
如何让信号注册结束在子进程之前
设置阻塞信号集,信号注册完之前,子进程阻塞,信号发不了。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include<sys/stat.h>
#include <signal.h>
#include<sys/wait.h>void myFun(int num){printf("捕捉到的信号:%d\n",num);//回收子进程PCB的资源while(1){int ret=waitpid(-1,NULL,WNOHANG);if(ret>0){printf("child die,pid=%d\n",ret);}else if(ret==0){//说明还有子进程活着break;}else if(ret==-1){//所有子进程结束了break;}}}int main(){//提前设置好阻塞信号集,阻塞sigchld因为有可能子进程很快结束,父进程还没有注册完sigset_t set;sigemptyset(&set);sigaddset(&set,SIGCHLD);sigprocmask(SIG_BLOCK,&set,NULL);//创建一些子进程pid_t pid;for(int i=0;i<20;i++){pid=fork();if(pid==0){break;}}if(pid>0){//父进程//捕捉子进程死亡时发送的sigchld信号struct sigaction act;act.sa_flags=0;act.sa_handler=myFun;sigemptyset(&act.sa_mask);sigaction(SIGCHLD,&act,NULL);//注册完信号捕捉以后,解除阻塞sigprocmask(SIG_UNBLOCK,&set,NULL);while(1){printf("parent process pid:%d\n",getpid());sleep(2);}}else if(pid==0){//子进程printf("child process pid:%d\n",getpid());}return 0;
}

http://www.ppmy.cn/news/1543894.html

相关文章

【Rust练习】18.特征 Trait

练习题来自&#xff1a;https://practice-zh.course.rs/generics-traits/traits.html 1 // 完成两个 impl 语句块 // 不要修改 main 中的代码 trait Hello {fn say_hi(&self) -> String {String::from("hi")}fn say_something(&self) -> String; }str…

2023数学分析【南昌大学】

计算 求极限 lim ⁡ n → ∞ ( 1 n 2 + 1 2 + 1 n 2 + 2 2 + ⋯ + 1 n 2 + n 2 ) \mathop{\lim }\limits_{n \to \infty } \left( \frac{1}{{\sqrt {n^2 + 1^2} }} + \frac{1}{{\sqrt {n^2 + 2^2} }} + \cdots + \frac{1}{{\sqrt {n^2 + n^2} }} \right) n→∞lim​(n2+12 ​1…

2022 NOIP 题解

建造军营 这道题之前做过一次,我们来转换一下这道题的题意&#xff0c;题中给到了边、点我们可以想到强连通分量&#xff0c;进而想到tarjan算法。通过所给样例及题意&#xff0c;我们可以将原题目转化为以下内容&#xff1a; 给定一张图&#xff0c;选择一些点和边&#xff…

redis分布式锁在项目中的应用总结

项目应用 应用1 redis分布式锁实现两个操作的原子性 需求&#xff1a;实现一人一单业务逻辑时&#xff08;如果能走到这个逻辑&#xff0c;代表库存是充足的&#xff09;&#xff0c;我们需要 先查询订单 如果订单不存在即没有买过则创建订单 这两个步骤我们要保证是原子…

6、磁盘管理

如何对硬盘进行分区&#xff1f;创建文件系统&#xff1f;挂载&#xff1f; 如何自动挂载&#xff1f; 硬盘概念 基本概念 硬盘是一种计算机的存储设备&#xff0c;通常是由一个或多个磁盘片组成&#xff0c;硬盘可以安装在计算机的内部&#xff0c;也可以外接计算机&#x…

【搜索引擎】俄罗斯搜索引擎yandex

俄罗斯搜索引擎yandex 1997年&#xff0c;俄罗斯搜索引擎Yandex&#xff08;俄语意为&#xff1a;语言目录&#xff09;首次上线&#xff0c;已发展成为全球第四大搜索引擎和第二大非英语搜索引擎 https://yandex.com/

新能源汽车火灾应急处置程序

摘要&#xff1a;新能源汽车在人们的日常生活中被广泛应用&#xff0c;但其消防安全问题也逐渐凸显。本文分析了新能源汽车的起火原因、燃烧危害性&#xff0c;并着重阐述了新能源汽车发生火灾后消防应急处置程序及应对措施等。 关键词&#xff1a;新能源汽车&#xff1b;火灾…

opencascade源码学习之Convert包

Convert_CircleToBSplineCurve 圆转多义线 Convert_CircleToBSplineCurve Convert_CompBezierCurves2dToBSplineCurve2d Bezier转样条曲线 Convert_CompBezierCurvesToBSplineCurve non-rational Bezier curve转样条曲线 Convert_CylinderToBSplineSurface 圆柱体转换为…