linux 进程间通信 1.4 — 信号

信号

(老规矩膜拜大佬)
对于 Linux来说,实际信号是软中断,许多重要的程序都需要处理信号。信号,为 Linux 提供了一种处理 异步事件 的方法。比如,终端用户输入了 ctrl+c 来中断程序,会通过信号机制停止一个程序。

信号概述

  1. 信号的名字和编号:
    每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO ”、“SIGCHLD”等等。
    信号定义在signal.h头文件中,信号名都定义为正整数。
    具体的信号名称可以使用 kill -l 来查看信号的名字以及序号,信号是从1开始编号的,不存在0号信号。kill对于信号0又特殊的应用。

在这里插入图片描述
信号的简单使用:
据上图 : 常用的 kill 命令就是一个发送信号的工具,kill -9
PID
PID 指 使用 ps -aux|grep ./a.out 后,可以查看到 ./a.out 的进程的 id 号,选择此 id 号便可以杀死此进程,同理 kill -SIGKILL PID 亦可以杀死进程,SIGKILL 的编号即 9

2.信号的处理:
信号的处理有三种方法,分别是:忽略、捕捉和默认动作
忽略信号,大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILL和SIGSTOP,一般是怎么写也杀不死的)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景
捕捉信号,需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。
系统默认动作,对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。
具体的信号默认动作可以使用man 7 signal来查看系统的具体定义。

小试牛刀
首先:
2) SIGINT
程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。

  1. SIGQUIT
    和SIGINT类似, 但由QUIT字符(通常是Ctrl-)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。

  2. SIGTERM
    程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。

  3. SIGSTOP
    停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.

在 linux 中,
查找进程,可以用: ps aux|grep +进程名
查找头文件包含的所有函数,可以用:vi /usr/include/头文件名

我们来试一个 使用 ctrl c 后,不退出进程的程序
#include <signal.h>
#include <stdio.h>
//       typedef void (*sighandler_t)(int);
//              其定义了一个 sighandler_t 的类型,其类型表示指向 返回值为 void,参数为 int 的指针,可以用来声明一个/多个 函数指针
//              C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字>。

//       sighandler_t signal(int signum, sighandler_t handler);
        // sigum 是指的 信号的 编号,sighandler_y hander 则表示,一个指向 
void handler(int signum){
        printf("get signum = %d\n",signum);
        printf("never quit \n");
}
int main(){
        signal(SIGINT,handler);
        while(1);
        return 0;
}

signal 函数,分别注册了一个信号处理函数,一个信号 sigum ,对于已经注册的信号(例子中为:SIGINT),对信号的处理是明显的捕捉信号,捕捉的信号 SIGINT,而后由函数 handler 进行处理。

运行结果:在这里插入图片描述
但是,我们也不能让其一直挂着不是(学习一波代码,坏一坏电脑吗),所以我们用信号处理中,那两个不能忽略的信号, SIGKILL和SIGSTOP 使用 kill -9 杀死进程
在这里插入图片描述

kill 函数

前面我们使用键盘的方式进行了信号的发送,现在我们来不使用键盘的方式进行信号的发送吧。

先来看 kill 函数
NAME
       kill - send signal to a process

SYNOPSIS
       #include <sys/types.h>
       #include <signal.h>
       int kill(pid_t pid, int sig);
	信号的处理需要有接受者,显然发送者必须要知道发给谁,
	pid 就是接受者的 pid,sig 则是发送的信号的类型。
必须注意的是,当在 linux 命令行中,输入的皆是以字符串的形式
而 pid_t 和 int signum 都是整型数,所以我们要转换一下
atoi 函数便是将 字符串 转换为 整型数的一种方式(其返回值为对应的整型数)
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
int main(int argc, char ** argv ){
        int signum;
        int pid;
        signum = atoi(argv[1]);
//      atoi 一个把字符串转化为整型数的一个函数,其返回值为 整型数
        pid = atoi(argv[2]);
        printf("num = %d, pid = %d \n",signum,pid);
// #include <sys/types.h>
// #include <signal.h>
// int kill(pid_t pid, int sig);
//   参数:
//   pid:可能选择有以下四种
//   1. pid大于零时,pid是信号欲送往的进程的标识。
//   2. pid等于零时,信号将送往所有与调用kill()的那个进程属同一个使用组的进程。
//   3. pid等于-1时,信号将送往所有调用进程有权给其发送信号的进程,除了进程1(init)。
//   4. pid小于-1时,信号将送往以-pid为组标识的进程。
//
//   sig:准备发送的信号代码,假如其值为零则没有任何信号送出,但是系统会执行错误检查,通常会利用sig值为零来检验某个进程是否仍在执行。
//   返回值说明: 成功执行时,返回0。失败返回-1,errno被设为以下的某个值 EINVAL>:指定的信号码无效(参数 sig 不合法) EPERM;权限不够无法传送信号给指定进程 ESRCH:参数 pid 所指定的进程或进程组不存在
        kill(pid,signum);
        printf("send signal is ok \n");

        return 0;
}

这样就可以吧信号发送给其他的进程了,根据 pid 号,我们可以 ps aux|grep sign 来查询之前接受消息的进程的 pid 号,
在这里插入图片描述

windows

现在我们在windows 中进行搞一次吧
windows(不仅仅windows,system也用于 linux)

函数名: system
功 能: 发出一个DOS命令
用 法: int system(char *command);
system(“pause”)可以实现冻结屏幕,便于观察程序的执行结果;system(“CLS”)可以实现清屏操作。而调用color函数可以改变控制台的前景色和背景

然而,dos 作为一个字符串,我们既然要手动输入,那就只能使用 main 函数的两个参数,但是这样的话,我们就有一个问题,那便是,这两个参数,如何去构成一个字符串呢?

这里我们使用 sprintf 函数
sprintf指的是字符串格式化命令
函数声明为 int sprintf(char *string, char *format [,argument,…]);
主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串。

在这里插入图片描述
功能:
把格式化的数据写入某个字符串缓冲区。
返回值
如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。
如果失败,则返回一个负数。

好了,开工干活

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

int main(int argc, char ** argv ){
        int signum;
        int pid;
        char cmd[128] = {0};

        signum = atoi(argv[1]);
//      atoi 一个把字符串转化为整型数的一个函数,其返回值为 整型数
        pid = atoi(argv[2]);
        printf("num = %d, pid = %d \n",signum,pid);

//      kill(pid,signum);
//      system是一个C/C++的函数。windows操作系统下system () 函数详解主要是在C语言中的应用,system函数需加头文件<stdlib.h>后方可调用。
//      函数名: system
//      功 能: 发出一个DOS命令
//      用 法: int system(char *command);
        sprintf(cmd,"kill -%d %d",signum,pid);
        //	制作一个纯粹的
        system(cmd);
        printf("send signal is ok \n");
        return 0;
}

游戏结束 over

结束尼玛
最后我们来说一下

信号的忽略

信号的忽略,在 linux 中,提供了一个忽略信号的信号,我们在 man 2 手册中,搜索 SIG 可以直接查看
在这里插入图片描述

所以,我们只需要把前面的

signal(SIGINT,handler); —— 改成 signal(SIGINT,SIG_IGN);
即可忽略 ctrl c 的信号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值