文章目录
前言
一、管道(Pipes)
管道示例代码:
管道示例流程解读:
管道示例运行效果:
二、消息队列(Message Queues)
消息队列示例代码
消息队列示例流程解读:
消息队列示例执行效果
三、共享内存(Shared Memory)
共享内存示例代码
共享内存示例流程解读:
共享内存示例执行效果
四、 信号(Signals)
信号示例代码:
信号示例流程解读:
信号示例执行效果
五、套接字(Sockets)
套接字示例代码:
套接字示例流程解读:
套接字示例执行结果
六、信号量(Semaphores)
信号量示例代码:
信号量示例流程解读:
信号量示例执行结果
七、文件映射(Memory-Mapped Files)
文件映射示例代码:
文件映射示例流程解读:
文件映射示例执行结果
总结
前言
线程和进程间的通讯(Inter-Process Communication, IPC)是操作系统中的一个重要概念,用于实现不同进程或同一进程中的不同线程之间的数据交换和协调。 但是这些概念太多了,容易搞混了,所有特地写了这篇博客来记录这些方式的使用实例,建立大家收藏起来,将来需要复习的时候,再来看一看,能够快速的带你复习一遍!
以下是几个常见的进程间通信的方式:管道、消息队列、共享内存、信号、套接字、信号量、文件映射
提示:以下是本篇文章正文内容,下面案例可供参考
一、管道(Pipes)
管道是一种半双工的通信方式,数据只能单向流动。管道分为两种类型:
匿名管道:仅限于具有亲缘关系的进程之间使用,通常用于父子进程之间的通信。 命名管道(FIFO):可以在任意两个进程之间使用,通过文件系统中的一个特殊文件来标识。
管道示例代码:
以下是一个简单的 C 语言示例,演示如何使用管道实现父子进程间的通信。
#include
#include
#include
#include
#include
int main() {
int pipefd[2];
pid_t pid;
char buf[100];
if (pipe(pipefd) == -1) {
perror("pipe");
return 1;
}
pid = fork();
if (pid == -1) {
perror("fork");
return 1;
}
if (pid == 0) {
// 子进程
close(pipefd[0]); // 关闭读端
write(pipefd[1], "Hello from child", 18);
close(pipefd[1]);
} else {
// 父进程
close(pipefd[1]); // 关闭写端
memset(buf, 0, sizeof(buf)); // 清空缓冲区
ssize_t bytes_read = read(pipefd[0], buf, sizeof(buf) - 1); // 读取数据,留一个字节给终止符
if (bytes_read > 0) {
printf("Received: %s\n", buf);
} else {
perror("read");
}
close(pipefd[0]);
wait(NULL);
}
return 0;
}
管道示例流程解读:
1、创建管道:使用 pipe 函数创建一个管道,该函数返回两个文件描述符,分别用于读取和写入。
2、创建子进程:使用 fork 函数创建一个子进程。fork 返回子进程的 PID,如果返回值为 -1 表示出错,0 表示当前是子进程,其他值表示当前是父进程。
3、关闭不必要的管道端: 在父进程中,关闭管道的端(pipefd[1]),因为子进程只读取数据。 在子进程中,关闭管道的读端(pipefd[0]),因为父进程只写入数据。
4、数据传输: 子进程使用 write 函数向管道中写入数据。 父进程使用 read 函数从管道中读取数据。
5、关闭管道:在完成数据传输后,关闭管道的相应端。
6、等待子进程结束:父进程使用 wait 函数等待子进程结束。
管道示例运行效果:
二、消息队列(Message Queues)
消息队列是一种更高级的通信方式,允许进程发送和接收消息。消息队列可以存储多个消息,并且可以设置消息的优先级。
消息队列示例代码
#include
#include
#include
#include
#include
#include
#include
#define MAX_MSG_SIZE 256
// 定义消息结构体
struct msg_buffer {
long msg_type;
char msg_text[MAX_MSG_SIZE];
};
int main() {
key_t key;
int msgid;
struct msg_buffer message;
pid_t cpid;
// 生成一个唯一的键值
key = ftok("/etc/passwd", 65); // 使用现有的文件 /etc/passwd
if (key == -1) {
perror("ftok");
exit(EXIT_FAILURE);
}
// 创建消息队列
msgid = msgget(key, 0666 | IPC_CREAT);
if (msgid == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
// 创建子进程
cpid = fork();
if (cpid == -1) {
// fork 失败
perror("fork");
exit(EXIT_FAILURE);
} else if (cpid == 0) {
// 子进程
// 子进程接收消息
if (msgrcv(msgid, &message, sizeof(message.msg_text), 1, 0) == -1) {
perror("msgrcv");
exit(EXIT_FAILURE);
}
printf("Child process received: %s\n", message.msg_text);
// 子进程发送消息
message.msg_type = 2;
strcpy(message.msg_text, "Hello from child");
if (msgsnd(msgid, &message, sizeof(message.msg_text), 0) == -1) {
perror("msgsnd");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
} else {
// 父进程
// 父进程发送消息
message.msg_type = 1;
strcpy(message.msg_text, "Hello from parent");
if (msgsnd(msgid, &message, sizeof(message.msg_text), 0) == -1) {