第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > c语言多进程之进程间通信IPC:信号操作函数之signal kill

c语言多进程之进程间通信IPC:信号操作函数之signal kill

时间:2019-12-29 11:12:11

相关推荐

c语言多进程之进程间通信IPC:信号操作函数之signal kill

信号:是一种特殊的IPC(进程间通讯),它是系统里面已经设计好了的,我们只能去使用它,且是一种异步通信方式

关于linux下的信号:

(1).一共有64个信号值;可以用:kill -l 命令查询所有的信号值

(2).前面1-31种信号值是不可靠信号值(非实时信号),同时发送多个一样的信号只会响应第一个信号,后面的会忽略掉;

(3).后面32-64是后来添加的是可靠的信号值(实时信号值) ,无论发送多少个一样的信号都会一一响应

(4).比较常用的信号有:
2号SIGINT:终止一个进程(ctrl + c);
9号SIGKILL:强制杀死一个进程;
18号SIGCONT:回复一个进程的运行(之前已经执行了 SIGSTOP 这个暂停信号);
19号SIGSTOP:暂停一个进程的运行,并没有结束掉

5.信号间可以嵌套,但是会按接收到的顺序逐一响应,接收到多个相同的不可靠信号(1-31号信号)只会执行一个

一、信号中的kill和killall

(1)命令使用kill和killall指令发送信号给某一进程:

(1)kill -信号值 进程的pid号

(注:可先使用ps -ef查看目前系统正在运行的所有进行及其进程号等进程信息)

(2)killall -信号值 进程的名字

(2)代码使用kill函数发送信号给某一进程:

函数作用:

给一个进程发送信号

函数原型:

#include <sys/types.h>#include <signal.h>int kill(pid_t pid, int sig);

函数形参:

pid:想要用于接收发送出去的信号的进程pid号

sig:需要发送的信号值

函数返回值:

成功返回0

失败返回-1

测试代码:

/**测试kill代码实现*/#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <unistd.h>#include <signal.h>int main(){//创建一个子进程pid_t id = fork();if(id<0){perror("fork failed");return -1;}else if(id==0){printf("hello world\n");//把自己杀掉kill(getpid(),9);printf("i am child\n");}printf("hello world\n");//退出程序并且刷新缓冲区exit(0);}

运行结果:

(1)因为子进程的中的kill(getpid(),9);,把自己pid获取到后把自己杀掉了,因此下面那一句”i am child“没有输出

一、信号中的signal等函数

进程对信号的操作主要有:

1、缺省 —》执行默认动作

2、捕捉 —》接收到信号后,执行自己规定的动作

3、忽略 —》接收到信号后,不执行任何操作

4、阻塞 —》接收到信号后,不立即响应,等该信号被解除阻塞,再响应(延迟响应)

(注:9,18,19这几个信号不可捕捉,忽略,阻塞;否则所有进程都忽略了这几个函数所有进程将变成精灵进程,当进程创建到达最大数时将会导致系统奔溃)

1.捕捉与忽略信号函数signal

函数原型:

#include <signal.h>typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);

函数形参:

typedef void (*sighandler_t)(int):宏定义了一个函数指针,返回值类型为void,形参类型为:int

signum:需要捕捉的信号值

handler:本质是一个指针函数,接受接收到相应信号执行的函数,也可使用:

SIG_IGN —》忽略

SIG_DFL —》执行默认动作

函数返回值:

成功:返回前一个这个信号处理的回调函数的指针

出错:出现错误时,返回SIG_ERR

测试代码:

/*信号相关函数测试*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <signal.h>void handel(int num){if(num == 2){printf("catch the 2 signal\n");}else if(num == 3){printf("catch the 3 signal\n");}else if(num == 4){printf("catch the 4 signal\n");}}int main(){//捕捉2,3,4号信号,并且执行相对应的函数signal(2,handel);signal(3,handel);signal(4,handel);//创建一个子进程while(1){printf("hello world\n");sleep(1);}//退出程序并且刷新缓冲区exit(0);}

运行结果:

(1)当捕捉到2,3,4号信号时将执行相对应的代码,且不再执行系统默认动作

(2)当signal(int signum, sighandler_t handler);的handler设置SIG_IGN时接收到相对应的信号时将不执行任何动作

(3)当signal(int signum, sighandler_t handler);的handler设置SIG_DFL时接收到相对应的信号时将执行系统默认的动作(和正常使用效果一样)

2.阻塞相关信号函数:

阻塞时,该信号不执行,等待解除阻塞再执行该信号,并且如果是1-31号的信号,发送多个相同信号也只会执行一次

常用的阻塞信号函数原型:

//一个信号列表(集合)sigset_t set;//信号值int signum;//清空一个信号列表(集合)int sigemptyset(sigset_t *set);//把所有的信号都加入一个信号列表(集合)int sigfillset(sigset_t *set);//把某一个信号都加入一个信号列表(集合)int sigaddset(sigset_t *set, int signum);//把某一个信号从一个信号列表(集合)删除int sigdelset(sigset_t *set, int signum);//判断一个信号是否在一个信号列表(集合)int sigismember(const sigset_t *set, int signum);//把一个信号列表(集合)设置为阻塞状态或解除阻塞//how:(1)SIG_BLOCK:在原有的阻塞信号中再添加信号列表(集合)中的信号// (2)SIG_UNBLOCK:在原有阻塞信号基础上(在阻塞信号中找)解除信号列表(集合)中的信号// (3)SIG_SETMASK:把原有的阻塞信号全部替换成信号列表(集合)中的信号////const sigset_t *set:新的信号列表(集合)//sigset_t *oldset:原有的信号列表(集合)int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

函数的返回值:

成功:sigismember返回1,其他函数均为返回0

失败:sigismember返回0,其他函数均为返回-1

测试代码:

/**信号阻塞测试代码*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <signal.h>int main(){//定义一个信号列表(集合)sigset_t set;//清空一下信号列表(集合)sigemptyset(&set);//添加信号到信号列表sigaddset(&set,2);sigaddset(&set,3);sigaddset(&set,4);//设置信号列表为阻塞sigprocmask(SIG_SETMASK, &set, NULL);int i=0;while(1){//判断i是否为20,如果是就解除阻塞if(i==20){//解除信号阻塞sigprocmask(SIG_UNBLOCK, &set, NULL);}//最后看会不会打印这行printf("hello world\n");sleep(1);//每次加1i++;}//退出程序并且刷新缓冲区exit(0);}

运行结果:

(1)虽然一开始从代码开始运行就发送了信号过去,当前为阻塞为阻塞状态,收到的信号会等解除阻塞再去执行
(2)其实只执行了第一个信号,因为第一个信号就把进程终结掉了,后面的并没有执行,以至于最后打印了一个找不到这个进程

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。