赞
踩
目录
进程间通信又称为IPC技术
进程特性:数据无法共享(数据无论是全局变量还是局部变量作用域在哪,都是无法共享的)(因为进程中的PCB管理单独处理数据)
因为数据无法共享,数据不能互通,因此采用进程间通信的技术来完成进程间的传输数据
进程间通信的技术总共有6种,每一种都有各自的使用场景和优缺点,在之后文章中会深入学习IPC技术
Qt中学习的信号和槽机制就是模仿Linux的信号来实现的。
信号:在某一个时刻,发出的一个能够提示对方的一种消息(信号)
信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动
信号是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等
它们由shell和终端管理器产生以引起中断
进程可以生成信号、捕捉并响应信号或屏蔽信号
kill应该理解为发送 ,发送第几个信号给某个进程
每一个信号前面都有一个编号 ,看到第九个信号SIGKILL,这个信号的动作才是杀死进程
kill -9 (发送第九个信号 而第九个信号的功能才是杀死进程)
细看发现,有信号编号的缺失,如上图中31后没有32 33
这是作为区分(区分可靠信号和不可靠信号)
说明了编号1-31的信号称为不可靠信号,从编号34-64的称为可靠信号
编号31之前的很多名称都不一样(不可靠信号)
而编号34之后的都SIGRTMIN SIGRTMAX有关(可靠信号)
用户自定义信号:注意SIGUSR1和SIGUSR2 ,这两个叫用户定义信号【不可靠信号】,
这两个信号没有具体的系统含义,也就是说这两个信号发出,操作系统没有任何意义(对操作系统来说不知道这两个信号是什么作用)
这个用户定义信号就是编程开发人员可以利用这两个信号来进行编程的,可以把这些信号写上一些作用,发送接收到这个信号的时候,可以进行自己所想要实现的一些相关操作(自己去定义这个信号的作用),预留自定义信号提供给开发人员使用
用户自定义信号1 编号为10
用户自定义信号2 编号为12
均为不可靠信号
功能:
什么信号发送,应该执行什么函数 (什么信号去关联什么函数) 类似Qt中的connect
其中的sig 就是kill -l 查看到的信号的ID号,第一个参数sig就是信号的一个ID
void(*func)(int):函数指针,函数指针是指针,指针指向的那个函数所存在的那个内存空间
为什么参数用到函数指针?:当进程接收信号的时候会采取相应的行动,这个所谓相应的行动其实就是某一个函数的逻辑过程,而这个函数是什么是通过一个函数指针来指向
(类似Qt中的信号和槽,有什么信号,信号所关联的槽函数是哪个,关联,当信号发生后那个槽函数就默认被调用
写一个connect作为连接,有带四个参数,谁发送什么信号,谁接收之后执行某一个槽函数 Qt本来就是Linux操作系统下所编译开发出来的程序,
Qt中的信号和槽就是模仿Linux的信号来实现的)
kill -9 xxx:发送第九个信号给某个进程,第九个信号具备的功能是让某个进程停止
进程可以通过调用kill向包括它本身在内的另一个进程发送信号
如果程序没有发送该信号的权限,对kill的调用就将失败
功能:
给什么进程(PID),发送信号
kill函数的作用就是把参数sig给定的信号发送给标识号为pid的进程
要想发送一个信号,发送者进程必须拥有相应的权限
这通常意味着两个进程必须拥有同样的用户ID
查看绑定信号的函数
查看发送信号的函数
查看fork系统调用
信号绑定与信号发送 案例
- #include<iostream>
- #include <sys/types.h>
- #include <signal.h>
- #include <unistd.h>
-
- using namespace std;
-
- //信号处理函数
- void signal_function(int num)
- {
- cout << "signal_function 被触发 pid = " << getpid() << endl;
- }
-
- int main()
- {
- pid_t pid = 0;
- //信号绑定
- signal(SIGUSR1, signal_function);
-
- pid = fork();
- if (pid > 0)
- {
- sleep(5);
- //父进程给子进程发送信号
- kill(pid, SIGUSR1);
- while (1)
- {
- }
- }
- else if (pid == 0)
- {
- while (1)
- {
- cout << "子进程 pid = " << getpid() << endl;
- sleep(1);
- }
- }
- return 0;
- }
结果:
子进程5000ms后,死循环被中断去处理信号处理函数,做完后继续子进程
以上说明了信号的优先级是最高的 ,无论是否死循环,只要信号发送到位,就必须执行信号处理函数(信号特性:强制中断)
举个生活中实际例子就好比你正在工作,别人发送短信给你(信号),你回给别人消息后,继续做工作【就是你在工作的时候会被中断一下,然后继续工作】
做个测试:查看一下num
- //信号处理函数
- void signal_function(int num)
- {
- cout << "signal_function 被触发 pid = " << getpid() << "num = "<<num<< endl;
- }
num = 10 就是用户自定义信号1的 信号ID
做个测试:信号绑定和信号发送都换成SIGUSR2 [用户自定义信号2] num的结果就是12
做个测试:若是如下情况
信号绑定 SIGUSR1
信号发送 SIGUSR2
5000ms后,停止了
查看一下进程
70573是僵尸状态 (僵尸子先走完逻辑,父进程还在执行逻辑)
由上述知 信号特征:如果绑定一个信号,发送的是另外一个不认识的信号,这样会导致整个进程强制结束(即便走到断点return处,内存仍然没有被回收)
没有执行完逻辑(while死循环),进程始终结束不了(僵尸状态)
综合上述,绑定什么信号,就发送信号,才是一个正常的业务逻辑
做个测试:若是绑定多个信号,发送其中一个信号
是可行的
做个测试:使用for循环多次发送信号
- #include<iostream>
- #include <sys/types.h>
- #include <signal.h>
- #include <unistd.h>
-
- using namespace std;
-
- //信号处理函数
- void signal_function(int num)
- {
- cout << "signal_function 被触发 pid = " << getpid() << "num = "<<num<< endl;
- }
-
- int main()
- {
- pid_t pid = 0;
- //信号绑定
- signal(SIGUSR1, signal_function);
-
- pid = fork();
- if (pid > 0)
- {
- sleep(5);
- for (int i = 0; i < 3; i++)
- {
- //父进程给子进程发送信号
- kill(pid, SIGUSR1);
- }
-
- while (1)
- {
- }
- }
- else if (pid == 0)
- {
- while (1)
- {
- cout << "子进程 pid = " << getpid() << endl;
- sleep(1);
- }
- }
- return 0;
- }
虽然多次(for循环发送3次信号)发送信号,但是信号处理函数只走一次
发送来的信号,可能不会处理,也就是说明SIGUSR1和SIGUSR2是不可靠信号
对于这个问题,在发送信号中需要延时处理:sleep(1);
可以看出for循环3次发送信号,都有信号处理函数执行
不可靠信号的连续发送是有问题的,有可能会丢失
做个测试:换个可靠信号SIGRTMAX (不需要延时信号处理)
可以看出,可靠信号 多次发送信号(几次) 信号处理函数就执行几次
可靠信号 连续发送,发送的信号都会处理
由上述知道:
可靠和不可靠信号,对于信号连续发送(快速发送信号)的场景下,区别就显现出来了
编号31之前的是不可靠(快速连续发送信号容易丢失)
编号34后的是可靠信号(快速连续发送信号保证不丢失)
更多有关 IPC技术之信号 的学习在下面文章,感兴趣可以学习:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。