**进程间通讯(Interprocess Communication,IPC)**是指两个或多个进程间交换数据、信息和信号的过程。常见的进程间通讯方式有以下几种:
-
管道(Pipe):管道是一种基于文件的进程间通讯方式,可以用于父子进程间或者兄弟进程间通讯。管道有两种类型:匿名管道和命名管道。匿名管道只能用于有亲缘关系的进程间通讯,而命名管道可以用于没有亲缘关系的进程间通讯。
-
命名管道(FIFO):命名管道也是基于文件的进程间通讯方式,可以用于没有亲缘关系的进程间通讯。命名管道与匿名管道的不同之处在于,命名管道需要在文件系统中创建一个特殊的文件,用于在不同进程之间传递数据。
-
消息队列(Message Queue):消息队列是一种进程间通讯的方式,用于在不同进程之间传递消息。消息队列将消息存储在一个队列中,每个消息都有一个类型和一个数据部分,接收进程可以按照消息类型来获取相应的消息。
-
共享内存(Shared Memory):共享内存是一种特殊的进程间通讯方式,可以在不同进程之间共享同一个内存区域,实现高效的数据传输。共享内存通常需要使用信号量等同步机制来保证数据的一致性和安全性。
-
信号量(Semaphore):信号量是一种进程间同步的方式,用于控制多个进程对共享资源的访问。每个信号量有一个计数器和一个等待队列,当进程要访问共享资源时,需要先尝试获取信号量,如果信号量计数器大于0,则进程可以访问共享资源,并将信号量计数器减1;如果信号量计数器等于0,则进程需要等待,直到有其他进程释放信号量为止。
-
套接字(Socket):套接字是一种基于网络的进程间通讯方式,可以用于不同主机之间的进程间通讯。套接字通常使用 TCP 或 UDP 协议进行数据传输,需要使用 IP 地址和端口号来唯一标识一个套接字。套接字通常需要使用 select、poll 等多路复用技术来实现高效的网络通讯。
管道(Pipe)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
int fd[2];
pid_t pid;
if (pipe(fd) < 0) {
printf("pipe error!\n");
exit(1);
}
pid = fork();
if (pid < 0) {
printf("fork error!\n");
exit(1);
} else if (pid > 0) { // 父进程
close(fd[0]); // 关闭管道读端
char message[] = "Hello, child process!";
write(fd[1], message, sizeof(message)); // 向管道写入数据
close(fd[1]); // 关闭管道写端
} else { // 子进程
close(fd[1]); // 关闭管道写端
char buffer[100];
read(fd[0], buffer, sizeof(buffer)); // 从管道读取数据
printf("Message from parent process: %!s(MISSING)\n", buffer);
close(fd[0]); // 关闭管道读端
}
return 0;
}
在上面的代码中,父进程和子进程使用 pipe() 函数创建了一个管道,并通过管道进行通信。父进程先向管道写入一条消息,子进程再从管道读取该消息,并输出到控制台上。最后,父进程和子进程分别关闭管道的读端和写端。
消息队列(Message Queue)
import java.util.Scanner;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class MessageQueueExample {
public static void main(String[] args) {
BlockingQueue<Message> queue = new LinkedBlockingQueue<>(); // 创建消息队列
Producer producer = new Producer(queue); // 创建生产者线程
Consumer consumer = new Consumer(queue); // 创建消费者线程
producer.start(); // 启动生产者线程
consumer.start(); // 启动消费者线程
}
}
class Message {
private int type;
private String content;
public Message(int type, String content) {
this.type = type;
this.content = content;
}
public int getType() {
return type;
}
public String getContent() {
return content;
}
}
class Producer extends Thread {
private BlockingQueue<Message> queue;
public Producer(BlockingQueue<Message> queue) {
this.queue = queue;
}
@Override
public void run() {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("Enter message type (0 for quit): ");
int type = scanner.nextInt();
if (type == 0) {
scanner.close();
break;
}
System.out.print("Enter message content: ");
String content = scanner.next();
Message message = new Message(type, content);
try {
queue.put(message); // 将消息放入队列
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer extends Thread {
private BlockingQueue<Message> queue;
public Consumer(BlockingQueue<Message> queue) {
this.queue = queue;
}
@Override
public void run() {
while (true) {
try {
Message message = queue.take(); // 从队列中取出消息
if (message.getType() == 0) {
break;
}
System.out.println("Message type: " + message.getType() + ", content: " + message.getContent());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
在上面的代码中,使用 java.util.concurrent.BlockingQueue 实现了消息队列。队列中存放 Message 对象,每个 Message 对象包含一个消息类型和一个消息内容。使用 Producer 类来往队列中添加消息,使用 Consumer 类来从队列中取出消息并进行处理。Producer 和 Consumer 都是线程,分别对应消息队列中的生产者和消费者。在 Producer 中使用 Scanner 实现了从控制台输入消息的功能,当输入消息类型为 0 时,程序结束。在 Consumer 中使用 queue.take() 方法从队列中取出消息,当消息类型为 0 时,程序结束。