linux--进程信号

一、信号

1.信号的定义


是linux系统为了响应某些状况而产生的事件。进程收到信号后应该采取相应的措施

2. 哪些情况会引发信号?


1.键盘事件,如ctrl+ c ,ctrl+/(结束程序)
2.非法内存
3.硬件故障
4.环境切换

3.如何查看信号


通过指令kill -l查看
这里写图片描述

4.信号的默认处理方式


man 7 signal查看
这里写图片描述

5.常用信号解释


SIGINT ctrl+c发出的信号
SIGOUIT ctrl+\发出的信号
SIGUSER1 用户自定义信号,常用于发送与获取
SIGALRM 闹钟信号,用于倒计时
SIGPWR 关机,默认动作为终止进程
SIGSTOP 停止进程的执行,默认作为暂停处理
SIGKILL 无条件终止进程
SIGBUS 非法访问内存地址,默认为终止进程并产生core文件
SIGHUP 用户退出shell,默认终止进程
SIGSEGV 进程进行了无效的内存访问 ,默认动作为终止进程
SIGPIPE 向一个没有读端的管道写数据
SIGTERM 请求终止进程,kill命令缺省发送
SIGIO 此信号向进程指示发出一个异步IO事件
SIGWINCH 窗口大小改变时发出
SIGXCPU CPU时间限制超时
SIGXFSZ 进程超过文件大小限制
SIGTRAP 实现相关硬件异常
SIGILL 非法指令异常
SIGFPE 数学相关的异常,如被0除
SIGABRT 由调用abrot函数产生,进程非正常退出

6.进程收到信号的3种处理


1.默认:执行该信号的默认处理动作
2.忽略:信号来了不处理,丢掉信号SIGKILL SIGSTOP不可忽视
3.捕获并处理:信号来了。执行自己写的代码, SIGKILL SIGSTOP不能捕获

7.信号的分类


a.不可靠信号( 1-31不可靠):
linux的信号继承自早期的Unix信号,
Unix信号的缺陷:
1.信号处理函数执行完毕,信号恢复成默认处理方式(linux已改进)
2.会出现信号丢失,信号不排队
b.可靠信号 ( 34-64信号):
不会出现信号丢失,支持排队,信号处理函数执行完毕,不会恢复成缺省处理方式。
c.实时信号:就是可靠信号
d.非实时信号:就是不可靠信号

二、操作信号

1.注册信号


(1)signal函数


函数原型:typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

函数参数解释
signum:指明了所要处理的信号的类型,可取除SIGKILL与SIGSTOP外的任一种信号
sighandler_t handeler:信号执行函数,可取三种方式获得:
(1)自己定义函数
(2)SIG_IGN #define SIG_IGN ((sighandler_t)1) //忽略该信号
(3)SIG_DFL #define SIG_IGN ((sighandler_t)0) //默认处理

返回值:成功时返回信号处理函数指针
失败时返回SIG_ERR
SIG_ERR #define SIG_IGN((sighandler_t)(-1))

扫描二维码关注公众号,回复: 1028628 查看本文章

(2)代码实现:


1 
  2 #include <stdio.h>
  3 #include <signal.h>
  4 #include <unistd.h>
  5 #include <stdlib.h>
  6 
  7 void handler(int s)
  8 {
  9     printf("game over!\n");
 10     exit(0);
 11 }
 12 
 13 int main()
 14 {
 15     //ctrl+c
 16     signal(SIGINT,SIG_IGN);
 17     //crl+\信号
 18     signal(SIGQUIT,handler);
 19 
 20     for(;;)
 21     {
 22         printf("living!\n");
 23         sleep(1);
 24     }
 25 }
 26 

这里写图片描述

2.如何给某一进程发送信号


方式1:


kill -信号值 pid

方式2:


函数:
int kill(int pid,int signum)
返回值:成功返回0,失败返回-1
参数解释:
signum:信号值,及信号编号
pid:进程id,如下值:

    pid>0 ,发送给pid进程
    pid=0;调用者所在的进程组的任何一个进程
    pid=-1;有权发送的任何一个进程,除了1;

进程组:进程组有若干个进程
用管道连接的进程,fork创建出来的父子进程属于同一个进程组

后台进程:jobs 查看
fg %id 将后台进程调到前台(id是作业号,非进程号)
ctrl+c 只发给前台进程
前台进程:ctrl+z 前台转后台
直接以后台方式启动进程,(./a.out &)>a

代码实现:


  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <signal.h>
  5 
  6 void handler(int n)
  7 {
  8     printf("收到!\n");
  9 } 
 10 
 11 int main( void )
 12 {
 13     signal(SIGUSR1, handler);//用户自定义信号
 14     pid_t pid = fork();//创建子进程
 15     if (pid == 0 ) {
 16         sleep(1);
 17         kill(getppid(), SIGUSR1);
 18         exit(0);
 19     } else {
 20         while ( 1 ) { 
 21             printf("^_^\n");
 22             sleep(3);
 23         }
 24     }
 25     return 0;
 26 }

结果:
这里写图片描述

3.三个发送信号函数


给自己发信号: int rasie(int signum)
给进程组发送信号: int killpg(int pgrp,int sig)
暂停进程,直到信号被打断 int pause(void)

三、SIGALRM信号


1.alarm函数


int alarmint sec)
当sec规定的时间到了,触发SIGALRM信号,如果sec是0,表示清除信号
alarm(0)清除闹钟

返回值:若调用此函数前,进程已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0,失败返回-1

2.代码实现:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void handler(int s) {
    printf("超时\n");
    exit(1);
}

int main( void )
{
    char buf[100] = {};
    printf("name:");

    signal(SIGALRM, handler);

    alarm(3);
    scanf("%s", buf);
    alarm(0); // 清除闹钟


    printf("name=%s\n", buf);

    for ( ; ; ) {
        printf("OK\n");
        fflush(stdout);
        sleep(1);
    }
}

j结果:
这里写图片描述

四:简单的考试计时


  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <signal.h>
  4 #include <unistd.h>
  5 
  6 int X = 0;//错误数
  7 int V = 0;// 正确数
  8 
  9 void handler(int s) {
 10     printf("时间到\n");
 11     printf("V=%d, X=%d\n", V, X);
 12     exit(1);
 13 }
 14 
 15 int main( void )
 16 {
 17     signal(SIGALRM, handler);
 18     int i=0;
 19     alarm(20);
 20     srand(getpid());
 21     for ( i=0; i<10; i++) {
 22         int left = rand()%10;
 23         int right = rand()%10;
 24         printf("%d+%d=", left, right);
 25         int ret;
 26         scanf("%d", &ret);
 27         if ( left + right == ret ) {
 28             V++;

 29         } else {
 30             X++;
 31         }
 32     }
 33 
 34     printf("finish!\n");
 35     printf("V=%d, X=%d\n", V, X);
 36 }
 37 
 38 

结果:
这里写图片描述

good night!

猜你喜欢

转载自blog.csdn.net/kai29/article/details/80261208