Linux 进程与线程间通信方式及应用分析
文章目录
- Linux 进程与线程间通信方式及应用分析
- 1. 管道(Pipe)
- 1.1 匿名管道(Anonymous Pipe)
- 示例代码:
- 结果:
- 1.2 命名管道(FIFO)
- 示例代码:
- 结果:
- 优缺点:
- 2. 消息队列(Message Queue)
- 示例代码:
- 结果:
- 优缺点:
- 3. 共享内存(Shared Memory)
- 示例代码:
- 结果:
- 优缺点:
- 4. 信号(Signal)
- 示例代码:
- 结果:
- 优缺点:
- 5. 套接字(Socket)
- 示例代码:
- 结果:
- 优缺点:
- 总结
1. 管道(Pipe)
管道是 Linux 中最基础的进程间通信方式,通常用于父子进程之间的数据传输。它可以分为匿名管道和命名管道两种。
1.1 匿名管道(Anonymous Pipe)
匿名管道是最常见的进程间通信方式,通常由父子进程使用。它是通过内核缓冲区进行数据传输的,通信是单向的。
示例代码:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main() {
int pipe_fd[2];
pid_t pid;
char write_msg[] = "Hello from parent";
char read_msg[100];
// 创建管道
if (pipe(pipe_fd) == -1) {
perror("Pipe failed");
return 1;
}
pid = fork(); // 创建子进程
if (pid < 0) {
perror("Fork failed");
return 1;
}
if (pid > 0) { // 父进程
close(pipe_fd[0]); // 关闭读端
write(pipe_fd[1], write_msg, strlen(write_msg) + 1);
close(pipe_fd[1]); // 关闭写端
} else { // 子进程
close(pipe_fd[1]); // 关闭写端
read(pipe_fd[0], read_msg, sizeof(read_msg));
printf("Child process received: %s\n", read_msg);
close(pipe_fd[0]); // 关闭读端
}
return 0;
}
结果:
父进程通过管道写入数据,子进程通过管道读取数据。输出为:
Child process received: Hello from parent
1.2 命名管道(FIFO)
命名管道与匿名管道类似,但它允许不同的进程进行通信,即使它们没有亲缘关系。可以通过文件路径进行标识。
示例代码:
# 在终端中创建命名管道
mkfifo /tmp/myfifo
# 终端1
echo "Message from terminal1" > /tmp/myfifo
# 终端2
cat /tmp/myfifo
结果:
终端2会输出从终端1发送的消息。
优缺点:
优点 | 缺点 | 应用场景 |
---|---|---|
简单易用,适合父子进程通信。 | 只能在父子进程间通信,单向通信。 | 父子进程间简单的数据传递。 |
2. 消息队列(Message Queue)
消息队列是 Linux 提供的一种进程间通信机制,它允许进程之间通过消息进行通信。消息队列的特点是能够存储消息,且消息传递是异步的。
示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msg_buffer {
long msg_type;
char msg_text[100];
};
int main() {
key_t key;
int msgid;
struct msg_buffer message;
// 创建消息队列
key = ftok("progfile", 65);
msgid = msgget(key, 0666 | IPC_CREAT);
message.msg_type = 1;
strcpy(message.msg_text, "Hello from message queue");
// 发送消息
msgsnd(msgid, &message, sizeof(message), 0);
printf("Message sent: %s\n", message.msg_text);
// 接收消息
msgrcv(msgid, &message, sizeof(message), 1, 0);
printf("Message received: %s\n", message.msg_text);
// 删除消息队列
msgctl(msgid, IPC_RMID, NULL);
return 0;
}
结果:
进程通过消息队列发送和接收消息,成功传递数据。
优缺点:
优点 | 缺点 | 应用场景 |
---|---|---|
支持异步通信,消息可以排队。 | 有可能阻塞,消息队列最大长度有限。 | 高并发的进程间异步通信。 |
3. 共享内存(Shared Memory)
共享内存是最有效的进程间通信方式,允许多个进程共享一块内存区域。它的速度非常快,但需要考虑同步问题。
示例代码:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main() {
key_t key = 1234;
int shmid;
char *shm_ptr;
// 创建共享内存
shmid = shmget(key, 1024, 0666 | IPC_CREAT);
shm_ptr = (char*) shmat(shmid, NULL, 0);
// 写数据到共享内存
strcpy(shm_ptr, "Hello from shared memory");
// 读取共享内存数据
printf("Data read from shared memory: %s\n", shm_ptr);
// 分离共享内存
shmdt(shm_ptr);
// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
结果:
共享内存区的数据能够在多个进程间共享,提供高效的通信。
优缺点:
优点 | 缺点 | 应用场景 |
---|---|---|
速度快,效率高。 | 需要额外的同步机制,如互斥锁。 | 大量数据交换的高效通信。 |
4. 信号(Signal)
信号是一种简单的进程间通信方式,适用于处理事件或通知其他进程发生了某些事情。
示例代码:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void signal_handler(int signum) {
printf("Signal %d received!\n", signum);
}
int main() {
signal(SIGINT, signal_handler); // 捕获 SIGINT 信号
printf("Press Ctrl+C to send SIGINT signal...\n");
while (1) {
sleep(1);
}
return 0;
}
结果:
按下 Ctrl+C
发送 SIGINT 信号后,程序将捕获并响应该信号。
优缺点:
优点 | 缺点 | 应用场景 |
---|---|---|
简单易用,适合事件驱动的场景。 | 仅能传递简单的事件信息。 | 处理异步事件和信号通知。 |
5. 套接字(Socket)
套接字是跨进程(包括不同机器)的通信机制,可以在不同的进程间传递复杂的数据。
示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8080
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
char *message = "Hello from server";
// 创建 socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == 0) {
perror("Socket failed");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 绑定 socket
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
// 监听
if (listen(server_fd, 3) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
// 接受连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&address)) < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}
send(new_socket, message, strlen(message), 0);
printf("Message sent\n");
return 0;
}
结果:
使用套接字实现了服务器和客户端间的通信。
优缺点:
优点 | 缺点 | 应用场景 |
---|---|---|
支持跨主机通信,数据传输灵活。 | 编程较为复杂,需要理解网络协议。 | 远程进程间通信或分布式系统。 |
总结
通信方式 | 优点 | 缺点 | 应用场景 |
---|---|---|---|
管道 | 简单易用,适合父子进程通信。 | 只能单向通信,无法跨进程。 | 父子进程间数据传输。 |
消息队列 | 支持异步通信,消息排队。 | 阻塞问题,消息队列容量有限。 | 高并发的异步通信。 |
共享内存 | 高效,速度快。 | 需要同步机制。 | 高效数据交换。 |
信号 | 简单易用,适合事件通知。 | 只能传递简单信息。 | 异步事件通知。 |
套接字 | 支持跨主机通信,灵活多变。 | 编程复杂,需理解网络协议。 | 分布式系统,远程进程通信。 |
这些通信方式在实际开发中都有着广泛的应用,选择合适的通信方式可以有效提高系统的性能和可维护性。