信号的产生

1)终端按键产生信号(与终端交互的进程)

Ctrl + c  → 2) SIGINT(终止/中断)      "INT" ----Interrupt

Ctrl + z  → 20) SIGTSTP(暂停/停止)  "T" ----Terminal 终端  此时进程处于后台运行

Ctrl + \  → 3) SIGQUIT(退出)    

2)硬件异常产生信号

除0操作   → 8) SIGFPE (浮点数例外)    "F" -----float 浮点数。

非法访问内存  → 11) SIGSEGV (段错误)

总线错误  → 7) SIGBUS(内存未对齐)

3kill函数/命令产生信号

注意:kill函数或命令产生信号并不一定是要杀死进程,信号的含义是根据编号(或宏)来决定的,不是kill本身的含义。

kill命令向指定进程发送指定信号: kill –SIGKILL pid  // 终止该进程,向该进程发送9号信号   

kill函数向指定进程发送指定信号:

#include <sys/types.h>

#include <signal.h>

int kill(pid_t pid, int sig);

作用:向指定进程(pid)发送指定信号(sig),指定信号最好用宏表示,不用编号,因为在不同类型的操作系统中,信号的编号可能会不一样,用宏表示可以增强移植性。

返回值:成功0,失败-1(ID非法;信号非法;普通用户杀init进程等权级问题,即权限不够)。

pid > 0:发送信号给指定的进程。

pid = 0:发送信号给与调用kill函数进程属于同一进程组的所有进程(包括本身)。

pid < 0:取|pid|发给对应进程组。

pid = -1:发送给进程有权限发送的系统中所有进程(包括本身)。

进程组:每个进程都属于一个进程组,进程组是一个或多个进程集合,他们相互关联,共同完成一个实体任务,每个进程组都有一个进程组长,默认进程组ID与进程组长ID相同。

权限保护:super用户(root)可以发送信号给任意用户,普通用户是不能向系统用户发送信号的。同样,普通用户也不能向其他普通用户发送信号,终止其进程。 只能向自己创建的进程发送信号。普通用户基本规则是:发送者实际或有效用户ID == 接收者实际或有效用户ID

4raiseabort函数(系统调用产生,包括上面的kill函数)

raise函数:给当前进程发送指定信号(自己给自己发),则有:raise(signo) == kill(getpid(), signo);

#include <signal.h>

int raise(int sig);   成功:0,失败非0值

 

abort 函数:给自己发送异常终止信号 6) SIGABRT 信号,终止并产生core文件

#include <stdlib.h>

void abort(void);

5alarmsetitimer函数(软件条件产生)

设置定时器(闹钟)。在指定seconds后,内核会给当前进程发送14)SIGALRM信号。进程收到该信号,默认动作终止(结束进程)。每个进程都有且只有唯一个定时器。

#include <unistd.h>

unsigned int alarm(unsigned int seconds);成功:返回旧闹钟剩余的秒数,即该进程上一次调用alarm函数后还剩下的秒数;或者返回0(第一次调用alarm函数的时候)。无失败。

注意:alarm(0)表示取消闹钟,不是说0秒后终止进程,是取消闹钟。另外:定时与进程状态无关(自然时间),就绪、运行、挂起(阻塞、暂停)、终止、僵尸等,无论进程处于何种状态,alarm都计时。

例:alarm(5) → 3sec → alarm(4) → 5sec → alarm(5) →0sec→ alarm(0)

alarm(5)返回0   alarm(4)返回2    alarm(5)返回0   紧随着马上的alarm(0)返回5,并且取消闹钟。

time命令。 time ./zsx 查看程序zsx执行的时间,时间由三部分组成:程序在进程系统空间运行的时间+用户空间的时间+等待的时间(等待CPU、各种硬件资源等)=程序实际执行的时间。程序运行的瓶颈在于IO,优化程序,首选优化IO。

 

//练习:编写程序,测试你使用的计算机1秒钟能数多少个数。

#include <stdio.h>
#include <unistd.h>int main(void)
{int i;alarm(1);for(i = 0; ; i++)printf("%d\n", i);return 0;
}

#include <sys/time.h>

int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

作用:类似alarm函数,有四点不一样:1.setitimer函数对时间的计算方式有三种,用which参数指定,而alarm函数只有一种(自然时间);2. setitimer函数可以进行周期定时,即等待it_value时间后执行某一动作(收到信号),以后每隔it_interval时间再执行这一动作。而alarm函数只能实现等待it_value时间后执行某一动作(收到信号);3. setitimer函数可以精确到us级别,即其时间为tv_sec与tv_usec之和;4.返回值不一样。

返回值:成功0;失败-1,设置errno

参数which指定定时方式:1.自然定时:ITIMER_REAL → 14SIGALRM 计算自然时间;2.虚拟空间计时(用户空间):ITIMER_VIRTUAL → 26SIGVTALRM      只计算进程占用cpu的时间;3.运行时计时(用户+内核):ITIMER_PROF → 27SIGPROF  计算占用cpu及执行系统调用的时间(即相对于自然时间,不包括等待时间)。

参数new_value为传入参数,指定计时的大小,与alarm的参数作用一样;

参数old_value为传出参数,指定就旧闹钟剩余的秒数,作用类似alarm的返回值;结构体详细描述如下:

struct itimerval {

struct timeval it_interval; /* next value */   下一次定时的值(间隔时间)

    struct timeval it_value;    /* current value */  当前定时的值

};     // it_intervalit_value设置为0表示清零操作,即取消定时。

struct timeval {

time_t       tv_sec;         /* seconds */    s

    suseconds_t   tv_usec;        /* microseconds */  us

};

注意:每个进程都有且只有唯一个定时器。setitimer函数和alarm函数共用同一个定时器(闹钟)。

 

//练习: 使用setitimer函数实现alarm函数,重复计算机1秒数数程序。   

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>unsigned int my_alarm(unsigned int sec)    //实现alarm函数
{struct itimerval it, oldit;int ret;it.it_value.tv_sec = sec;it.it_value.tv_usec = 0;it.it_interval.tv_sec = 0;it.it_interval.tv_usec = 0;ret = setitimer(ITIMER_REAL, &it, &oldit);if (ret == -1) {perror("setitimer");exit(1);}return oldit.it_value.tv_sec;
}int main(void)
{int i;my_alarm(1);  //alarm(sec);for(i = 0; ; i++)printf("%d\n", i);return 0;
}

//拓展练习:测试it_intervalit_value这两个参数的作用。

#include <stdio.h>
#include <sys/time.h>
#include <signal.h>void myfunc(int signo)
{printf("hello world\n");
}int main(void)
{struct itimerval it, oldit;signal(SIGALRM, myfunc);   //注册SIGALRM信号的捕捉用户处理函数,signal函数用于对信号进行注册,真正捕捉该信号的是内核,内核捕捉该信号后就会去调用signal注册时对应的用户处理函数。    信号捕捉函数signal是一个典型的回调函数it.it_value.tv_sec = 5;it.it_value.tv_usec = 0;it.it_interval.tv_sec = 3;it.it_interval.tv_usec = 0;if(setitimer(ITIMER_REAL, &it, &oldit) == -1){perror("setitimer error");return -1;}while(1);return 0;
}

[root@localhost 01_signal_test]# ./setitimer1

hello world    //5s

hello world    //3s

hello world    //3s

hello world    //3s

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/385331.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

897. 递增顺序查找树

给定一个树&#xff0c;按中序遍历重新排列树&#xff0c;使树中最左边的结点现在是树的根&#xff0c;并且每个结点没有左子结点&#xff0c;只有一个右子结点。 示例 &#xff1a; 输入&#xff1a;[5,3,6,2,4,null,8,1,null,null,null,7,9]5/ \3 6/ \ \2 4 8/ …

信号集操作函数

内核通过读取未决信号集来判断信号是否应被处理。信号屏蔽字mask可以影响未决信号集。而我们可以在应用程序中自定义set来改变mask。已达到屏蔽指定信号的目的。综上&#xff1a;自定义信号集set&#xff08;也为一个字&#xff0c;64位&#xff09;通过信号集操作函数来改变信…

信号捕捉(signal、sigaction)

信号的基本属性&#xff1a;软中断&#xff0c;由内核发送&#xff0c;内核处理。某个进程通过内核向另一个进程发送信号时&#xff08;引起信号产生的五个因素&#xff09;&#xff0c;另一个进程将会陷入内核进行中断处理&#xff0c;未决信号集中相应信号置1&#xff0c;当递…

1090 Highest Price in Supply Chain (25)(25 分)

A supply chain is a network of retailers&#xff08;零售商&#xff09;, distributors&#xff08;经销商&#xff09;, and suppliers&#xff08;供应商&#xff09;-- everyone involved in moving a product from supplier to customer. Starting from one root suppli…

时序竞态(竞态条件)

产生原因&#xff1a;仍然以前文实现的sleep函数为例&#xff0c;如果进程在执行完alarm函数后&#xff0c;突然失去CPU&#xff0c;被阻塞等待&#xff08;这是有可能的&#xff0c;进程在执行过程中&#xff0c;若非原子操作&#xff0c;都有可能随时失去CPU&#xff09;&…

1106 Lowest Price in Supply Chain (25)

A supply chain is a network of retailers&#xff08;零售商&#xff09;, distributors&#xff08;经销商&#xff09;, and suppliers&#xff08;供应商&#xff09;-- everyone involved in moving a product from supplier to customer. Starting from one root suppli…

【Leetcode | 顺序刷题 】二分查找目录

二分查找序号题号129. 两数相除 50. Pow(x, n) 69. x 的平方根

sigsuspend函数(mysleep函数的改进)

可以通过设置屏蔽SIGALRM的方法来控制程序执行逻辑&#xff0c;但无论如何设置&#xff0c;程序都有可能在“解除信号屏蔽”与“挂起等待信号”这个两个操作间隙失去cpu资源。除非将这两步骤合并成一个“原子操作”。sigsuspend函数具备这个功能。在对时序要求严格的场合下都应…

【Leetcode | 顺序刷题】数学目录

序号题号1 7. 整数反转 28. 字符串转换整数 (atoi)39. 回文数443. 字符串相乘

全局变量的异步I/O问题

全局变量的异步I/O问题同样属于时序竞态问题&#xff0c;其本质就是多个进程或者同一个进程中的多个时序&#xff08;如主控程序和信号捕捉时的用户处理函数&#xff09;对同一个变量进行修改时&#xff0c;它们的执行顺序不一样就会导致该变量最终的值不一样&#xff0c;从而产…

【Leetcode | 03】String

字符串目录序号题号33. 无重复字符的最长子串 151. 翻转字符串里的单词

可/不可重入函数

一个函数在被调用执行期间&#xff08;尚未调用结束&#xff09;&#xff0c;由于某种时序&#xff08;递归或者处理信号捕捉时等情况&#xff09;又被重复调用&#xff0c;称之为“重入”。根据函数实现的方法可分为“可重入函数”和“不可重入函数”两种。看如下程序。 可以看…

【Leetcode | 顺序刷题】杂项目录

序号题号类别1136. 只出现一次的数字位运算2137. 只出现一次的数字 II位运算3 260. 只出现一次的数字 III 位运算4191. 位1的个数位运算5231. 2的幂位运算6342. 4的幂位运算7 338. 比特位计数 位运算8405. 数字转换为十六进制数位运算9371. 两整数之和位运算10401. 二进制手表位…

SIGCHLD信号

&#xff08;1&#xff09;SIGCHLD信号产生的条件 1.子进程终止时会向父进程发送SIGCHLD信号&#xff0c;告知父进程回收自己&#xff0c;但该信号的默认处理动作为忽略&#xff0c;因此父进程仍然不会去回收子进程&#xff0c;需要捕捉处理实现子进程的回收&#xff1b; 2.子…

信号传参

&#xff08;1&#xff09;发送信号传参 前面已经知道从一个进程向另一个进程发送信号可以使用kill函数&#xff0c;但是kill函数在向进程发送信号的时候不能携带除了信号以外的其他信息&#xff0c;这时可以使用与kill相对应的sigqueue函数&#xff0c;该函数也是向一个进程发…

【Leetcode | 52】257. 二叉树的所有路径

给定一个二叉树&#xff0c;返回所有从根节点到叶子节点的路径。 说明: 叶子节点是指没有子节点的节点。 示例: 输入: 1 / \ 2 3 \ 5 输出: ["1->2->5", "1->3"] 解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3 解法一&a…

623. 在二叉树中增加一行

给定一个二叉树&#xff0c;根节点为第1层&#xff0c;深度为 1。在其第 d 层追加一行值为 v 的节点。 添加规则&#xff1a;给定一个深度值 d &#xff08;正整数&#xff09;&#xff0c;针对深度为 d-1 层的每一非空节点 N&#xff0c;为 N 创建两个值为 v 的左子树和右子树…

终端的概念

操作系统接口&#xff1a;用户接口和程序接口。用户接口分为联机用户接口和脱机用户接口。脱机用户接口出现在早期的批处理系统中&#xff08;将作业提前交给操作系统&#xff0c;作业完成的过程中用户无法交互&#xff09;&#xff1b;联机用户接口即为终端&#xff08;所有输…

终端的启动流程

在Linux操作系统启动时&#xff0c;首先加载的进程就是init进程&#xff08;ID为1&#xff09;&#xff0c;其余进程都是init进程产生的&#xff08;fork&#xff0c;然后exec金蝉脱壳&#xff09;&#xff0c;因此系统中所有进程都可以看成是init进程的子孙进程。可以通过ps a…

进程组(作业)

&#xff08;1&#xff09;概念和特性 进程组&#xff0c;也称之为作业。BSD于1980年前后向Unix中增加的一个新特性。代表一个或多个进程的集合。每个进程都属于一个进程组。在waitpid函数和kill函数的参数中都曾使用到。操作系统设计的进程组的概念&#xff0c;是为了简化对多…