• 信号与进程间通信


    结束进程

    结束后台进程

    终端1:./main killed
    终端2:ps -ef |grep “main” 该命令找到进程的PID,使用命令kill +进程号删除该进程。在这里插入图片描述

    结束前台进程

    Ctrl + c :向终端发送一个信号 中断

    信号

    基本概念

    接收信号

    signal()函数
    我们结束前台进程使用的Ctrl+c就是使用了信号进行强制退出。
    信号是系统响应某个条件而产生的事件,进程接收到信号会执行相应的操作。
    与信号有关的系统调用在“signal.h”头文件中有声明
    信号的值在系统源码中的定义如下:

    1. #define SIGHUP 1
    2. #define SIGINT 2 //键盘按下 Ctrl+c 时,会产生该信号
    3. #define SIGQUIT 3
    4. #define SIGILL 4
    5. #define SIGTRAP 5
    6. #define SIGABRT 6
    7. #define SIGIOT 6
    8. #define SIGBUS 7
    9. #define SIGFPE 8
    10. #define SIGKILL 9 //该信号的响应方式不允许改变
    11. #define SIGUSR1 10
    12. #define SIGSEGV 11
    13. #define SIGUSR2 12
    14. #define SIGPIPE 13 //读端关闭的描述符,写端写入时产生,该信号会终止程序
    15. #define SIGALRM 14
    16. #define SIGTERM 15 //系统 kill 命令默认发送的信号
    17. #define SIGSTKFLT 16
    18. #define SIGCHLD 17 //子进程结束后,会默认给父进程发送该信号
    19. #define SIGCONT 18
    20. #define SIGSTOP 19
    21. #define SIGTSTP 20
    22. #define SIGTTIN 21
    23. #define SIGTTOU 22
    24. #define SIGURG 23

    参数:
    在这里插入图片描述

    发送信号

    kill()发送命令函数
    kill() 可以向指定的进程发送指定的信号:
    int kill(pid_t pid, int sig);
    pid > 0 指定将信号发送个那个进程
    pid == 0 信号被发送到和当前进程在同一个进程组的进程
    pid == -1 将信号发送给系统上有权限发送的所有的进程
    pid < -1 将信号发送给进程组 id 等于 pid 绝对值,并且有权限发送的所有的进程。 sig 指定发送信号的类型。
    在这里插入图片描述

    代码演示

    接收信号函数(signal)

    SIG_IGN

    int main(){
    	signal(SIGINT,SIG_IGN);
    	while(1){
    		printf("main over!!\n");
    		sleep(2);
    	}
    	exit(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    以上代码运行结果如下图,我们使用Ctrl+c无法进行退出,因为我们约定收到这个信号忽略这个信号。因此退出可以使用Ctrl+\。
    在这里插入图片描述

    SIG_DFL

    int main(){
    	signal(SIGINT,SIG_DFL);
    	while(1){
    		printf("main over!!\n");
    		sleep(2);
    	}
    	exit(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    SIG_DFL参数是约定按默认操作进行执行。使用Ctrl+c可以直接退出。
    在这里插入图片描述

    自定义函数

    在这里插入图片描述
    该函数我们是约定接收到命令之后调用fun函数使用,我们可以发现使用该函数,第一次接收到信号之后会执行输出命令,第二次接收命令之后会默认操作。
    在这里插入图片描述

    发送信号(kill)

    int main(int argc,char* argv[]){
    	if(argc!=2){
    		printf("argc error\n");
    		exit(1);
    	}
    	//int pid=atoi(argv[1]);
    	int pid;
    	sscanf(argv[1],"%d",&pid);
    	if(kill(pid,SIGINT)==-1){
    		perror("kill error");
    		exit(1);
    	}
    	exit(0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    我们使用main函数的参数调用进程的PID作为参数,然后使用sscanf函数讲字符串转换为整型,调用kill函数时使用SIGINT参数是同Ctrl+c相同的信号,所以会直接退出。
    在这里插入图片描述
    以上代码我们也可以做一修改,将信号作为参数使用,进行改变,如下
    在这里插入图片描述

    执行结果:在这里插入图片描述

    接收信号解决僵尸进程

    解决僵尸进程如下代码,使用的SIGCHLD参数是子进程结束会默认向父进程传递该信号,执行fun命令,wait(NULL)

    执行结果如下:在这里插入图片描述
    该方法比较于直接在函数父进程的if条件下等待优点是不需要等待子进程运行结束之后才能运行父进程。同时运行,子进程结束会自动发送信号接收子进程的退出码来解决僵尸进程。

  • 相关阅读:
    LeetCode每日一题(502. IPO)
    房屋差价能否作为非违约方的损失
    多肽标签Avi Tag,GLNDIFEAQKIEWHE
    分权分域有啥内容?
    机器学习入门(一)基本概念介绍
    11.30 WAVE SUMMIT+2022将在深圳举办,官网报名通道正式开启
    『现学现忘』Git基础 — 26、给Git命令设置别名
    【DRAM存储器十五】DDR介绍-关键技术之DLL和prefetch
    01. 信息搜集:Web 1~10
    【Java】泛型
  • 原文地址:https://blog.csdn.net/m0_56246173/article/details/128115860