进程间通信的方式
1. 进程间通信的几种方式
-
管道
比如 ls | grep 1;也就是将 进程 ls 拿到的结果作为 grep 1 这个进程的输入。实现了进程间的通信。
-
消息队列
消息队列就是我们的内核给我们创建的一种消息队列。我们可以往其中发送消息,也可以从其中接收消息。
-
共享内存
每个进程在访问内存的时候,会有虚拟内存地址和物理内存地址的一个映射。一般来说,俩个进程的虚拟内存地址可以是一样的,但是它们映射的物理内存地址是不一样的。共享内存就是将俩个进程的内存地址也是一样的。这个时候,俩个进程就可以访问共同的物理内存,实现通信。
-
套接字
比如访问数据库的进程和数据库进程本身之间的通信。
-
信号
信号就是说一个进程在运行的时候可以向另外的一个进程发送信号。
可以通过 kill -l 指令可以列举出所有的信号指令。kill 和信号有什么关系呢?linux 的信号大多数都是将一个进程杀死。
2. 进程间通过信号进行通信的几个例子
-
比如说使用命令 tail -f 1.txt, 运行了这个命令以后,这个进程会一直存在。那么怎么终止呢? ctrl + c, 就可以终止这个进程。其实这时候就是shell 终端进程向 运行的这个进程发送了一个 信号,这个信号的值其实是 SIGINT。
-
比如说使用命令 tail -f 1.txt, 运行了这个命令以后,这个进程会一直存在。那么怎么终止呢?还可以通过 kill + 进程号。其实这时候就是shell 终端进程向 运行的这个进程发送了一个 信号,这个信号的值其实是 Terminated。
-
比如说使用命令 tail -f 1.txt, 运行了这个命令以后,这个进程会一直存在。那么怎么终止呢?还可以通过 kill -9 + 进程号。其实这时候就是shell 终端进程向 运行的这个进程发送了 9号 信号,这个信号的值其实是 Killed。
3. 通过程序捕获信号
通过在程序中捕获信号,比如说,我们运行了一个java程序,但是我们想做到 ctrl + c , 和 kill + 进程号
,都不能终止这个进程,那么我们就可以捕获相应的信号。
- 程序如下:
package org.example;
import sun.misc.Signal;
import sun.misc.SignalHandler;
public class Main {
public static void main(String[] args) throws InterruptedException {
// 注册信号的处理。捕获 SIGINT 信号的处理。
Signal.handle(new Signal("INT"), new SignalHandler() {
@Override
public void handle(Signal signal) {
System.out.println(signal.toString() + "catched");
}
});
// 循环打印123
while (true) {
Thread.sleep(1000);
System.out.println(123);
}
}
}
-
通过 javac 命令编译这个程序
-
通过 java 命令运行这个程序 可以看到控制台打印了如下内容,并且通过ctrl + c不能终止这个进程
-
通过 kill + 进程号 终止这个进程。注意: Killed 这个信号是无法被捕获的,执行了 kill -9 ,那么这个进程必须被强制杀死。