首页 > 应用开发 > IT综合 > 进程通信实战:从管道到进程池的完整实现
# 进程通信实战:从管道到进程池的完整实现
在Linux系统编程中,进程通信是实现复杂系统的基础。本文将深入探讨匿名管道、命名管道和进程池的核心原理,并通过完整代码示例展示实际应用。
## 匿名管道:最简单的进程间通信
匿名管道是最基础的进程通信方式,适用于父子进程或兄弟进程间的单向数据流通信。
```c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
void anonymous_pipe_demo() {
int pipefd[2]; // pipefd[0]用于读,pipefd[1]用于写
pid_t pid;
char buffer[100];
// 1. 创建管道
if (pipe(pipefd) == -1) {
perror("pipe failed");
exit(1);
}
// 2. 创建子进程
pid = fork();
if (pid == -1) {
perror("fork failed");
exit(1);
}
if (pid == 0) { // 子进程 - 读取管道数据
close(pipefd[1]); // 关闭写端
// 从管道读取数据
ssize_t bytes = read(pipefd[0], buffer, sizeof(buffer));
if (bytes > 0) {
buffer[bytes] = '\0';
printf("Child received: %s\n", buffer);
}
close(pipefd[0]);
exit(0);
} else { // 父进程 - 写入管道数据
close(pipefd[0]); // 关闭读端
const char *message = "Hello from parent via pipe!";
write(pipefd[1], message, strlen(message));
close(pipefd[1]);
wait(NULL); // 等待子进程结束
}
}
```
### 双向通信的实现
```c
// 父子进程双向通信
void bidirectional_pipe_communication() {
int pipe1[2]; // 父写子读
int pipe2[2]; // 子写父读
pid_t pid;
if (pipe(pipe1) == -1 || pipe(pipe2) == -1) {
perror("pipe creation failed");
exit(1);
}
pid = fork();
if (pid == -1) {
perror("fork failed");
exit(1);
}
if (pid == 0) { // 子进程
close(pipe1[1]); // 关闭父写端
close(pipe2[0]); // 关闭父读端
char buffer[100];
// 读取父进程消息
ssize_t bytes = read(pipe1[0], buffer, sizeof(buffer));
if (bytes > 0) {
buffer[bytes] = '\0';
printf("Child: Received - %s\n", buffer);
}
// 回复父进程
const char *reply = "Message received, parent!";
write(pipe2[1], reply, strlen(reply));
close(pipe1[0]);
close(pipe2[1]);
exit(0);
} else { // 父进程
close(pipe1[0]); // 关闭子读端
close(pipe2[1]); // 关闭子写端
// 发送消息给子进程
const char *message = "Hello from parent!";
write(pipe1[1], message, strlen(message));
// 等待子进程回复
char response[100];
ssize_t bytes = read(pipe2[0], response, sizeof(response));
if (bytes > 0) {
response[bytes] = '\0';
printf("Parent: Child replied - %s\n", response);
}
close(pipe1[1]);
close(pipe2[0]);
wait(NULL);
}
}
```
## 命名管道(FIFO):无亲缘关系进程通信
命名管道允许任意进程通过文件系统路径进行通信。
```c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
// 创建命名管道(FIFO)
int create_named_pipe(const char *fifo_path) {
// 检查FIFO是否已存在
struct stat st;
if (stat(fifo_path, &st) == 0) {
if (S_ISFIFO(st.st_mode)) {
printf("FIFO %s already exists\n", fifo_path);
return 0;
} else {
fprintf(stderr, "%s exists but is not a FIFO\n", fifo_path);
return -1;
}
}
// 创建FIFO
if (mkfifo(fifo_path, 0666) == -1) {
if (errno != EEXIST) {
perror("mkfifo failed");
return -1;
}
}
printf("FIFO created: %s\n", fifo_path);
return 0;
}
// 写入者进程
void fifo_writer(const char *fifo_path) {
int fd;
char message[] = "Data from writer process";
// 打开FIFO进行写入(会阻塞直到有读取者打开)
printf("Writer: Waiting for reader...\n");
fd = open(fifo_path, O_WRONLY);
if (fd == -1) {
perror("open for writing failed");
return;
}
// 写入数据
if (write(fd, message, strlen(message)) == -1) {
perror("write failed");
} else {
printf("Writer: Data sent\n");
}
close(fd);
}
// 读取者进程
void fifo_reader(const char *fifo_path) {
int fd;
char buffer[256];
// 打开FIFO进行读取(会阻塞直到有写入者打开)
printf("Reader: Waiting for writer...\n");
fd = open(fifo_path, O_RDONLY);
if (fd == -1) {
perror("open for reading failed");
return;
}
// 读取数据
ssize_t bytes = read(fd, buffer, sizeof(buffer));
if (bytes > 0) {
buffer[bytes] = '\0';
printf("Reader: Received - %s\n", buffer);
} else if (bytes == -1) {
perror("read failed");
}
close(fd);
}
// 非阻塞FIFO操作
void nonblocking_fifo_operations(const char *fifo_path) {
int fd;
// 以非阻塞方式打开FIFO
fd = open(fifo_path, O_RDONLY | O_NONBLOCK);
if (fd == -1) {
perror("nonblocking open failed");
return;
}
char buffer[100];
ssize_t bytes;
while (1) {
bytes = read(fd, buffer, sizeof(buffer));
if (bytes > 0) {
buffer[bytes] = '\0';
printf("Received: %s\n", buffer);
break;
} else if (bytes == -1 && errno == EAGAIN) {
// 没有数据可用,继续等待
printf("Waiting for data...\n");
sleep(1);
} else {
perror("read error");
break;
}
}
close(fd);
}
```
## 进程池架构设计与实现
### 进程池核心结构
```c
#include <sys/socket.h>
#include <signal.h>
#include <sys/epoll.h>
#define MAX_PROCESSES 10
#define MAX_TASKS 100
// 任务结构
typedef struct {
int task_id;
void (*task_func)(void *);
void *task_data;
int priority;
} task_t;
// 工作进程结构
typedef struct {
pid_t pid;
int pipefd[2]; // 与主进程通信的管道
int is_busy; // 是否忙碌
int task_count; // 完成任务数
} worker_t;
// 进程池管理器
typedef struct {
worker_t workers[MAX_PROCESSES];
int worker_count;
int alive_count;
task_t task_queue[MAX_TASKS];
int queue_head;
int queue_tail;
int queue_size;
// 同步机制
pthread_mutex_t queue_lock;
pthread_cond_t queue_not_empty;
int shutdown; // 关闭标志
} process_pool_t;
```
### 进程池初始化
```c
// 初始化进程池
process_pool_t* process_pool_init(int worker_num) {
if (worker_num <= 0 || worker_num > MAX_PROCESSES) {
fprintf(stderr, "Invalid worker number\n");
return NULL;
}
process_pool_t *pool = malloc(sizeof(process_pool_t));
if (!pool) {
perror("malloc failed");
return NULL;
}
memset(pool, 0, sizeof(process_pool_t));
pool->worker_count = worker_num;
pool->alive_count = 0;
// 初始化同步原语
pthread_mutex_init(&pool->queue_lock, NULL);
pthread_cond_init(&pool->queue_not_empty, NULL);
// 创建工作进程
for (int i = 0; i < worker_num; i++) {
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe creation failed");
goto cleanup;
}
<"muy.h4k7.org.cn"><"bnd.h4k7.org.cn"><"wkm.h4k7.org.cn">
pid_t pid = fork();
if (pid == -1) {
perror("fork failed");
close(pipefd[0]);
close(pipefd[1]);
goto cleanup;
}
if (pid == 0) {
// 子进程 - 工作进程
close(pipefd[0]); // 关闭读端
worker_process(pipefd[1], i);
exit(0);
} else {
// 父进程 - 管理进程
close(pipefd[1]); // 关闭写端
pool->workers[i].pid = pid;
pool->workers[i].pipefd[0] = pipefd[0]; // 保留读端
pool->workers[i].is_busy = 0;
pool->workers[i].task_count = 0;
pool->alive_count++;
printf("Worker %d created (PID: %d)\n", i, pid);
}
}
printf("Process pool initialized with %d workers\n", worker_num);
return pool;
cleanup:
for (int i = 0; i < pool->alive_count; i++) {
kill(pool->workers[i].pid, SIGTERM);
waitpid(pool->workers[i].pid, NULL, 0);
}
free(pool);
return NULL;
}
```
### 工作进程实现
```c
// 工作进程主函数
void worker_process(int write_fd, int worker_id) {
printf("Worker %d (PID: %d) started\n", worker_id, getpid());
// 设置信号处理
signal(SIGINT, SIG_IGN);
signal(SIGTERM, worker_signal_handler);
// 工作循环
while (1) {
// 从管道读取任务
task_t task;
ssize_t bytes = read(STDIN_FILENO, &task, sizeof(task));
if (bytes <= 0) {
if (errno == EINTR) continue;
break; // 管道关闭或读取错误
}
// 执行任务
printf("Worker %d: Executing task %d\n", worker_id, task.task_id);
if (task.task_func) {
task.task_func(task.task_data);
}
// 通知主进程任务完成
task_result_t result = {
.worker_id = worker_id,
.task_id = task.task_id,
.status = 0
};
write(write_fd, &result, sizeof(result));
}
printf("Worker %d exiting\n", worker_id);
close(write_fd);
}
// 工作进程信号处理
void worker_signal_handler(int sig) {
printf("Worker %d received signal %d, exiting...\n", getpid(), sig);
exit(0);
}
```
### 任务调度与管理
```c
// 添加任务到队列
int process_pool_add_task(process_pool_t *pool,
void (*func)(void *),
void *data, int priority) {
if (!pool || pool->shutdown) return -1;
pthread_mutex_lock(&pool->queue_lock);
// 检查队列是否已满
if (pool->queue_size >= MAX_TASKS) {
pthread_mutex_unlock(&pool->queue_lock);
fprintf(stderr, "Task queue is full\n");
return -1;
}
// 创建新任务
static int task_id_counter = 0;
task_t task;
task.task_id = task_id_counter++;
task.task_func = func;
task.task_data = data;
task.priority = priority;
// 根据优先级插入队列
int pos = pool->queue_tail;
for (int i = pool->queue_head; i != pool->queue_tail;
i = (i + 1) % MAX_TASKS) {
if (pool->task_queue[i].priority < priority) {
pos = i;
break;
}
}
// 移动后续任务
for (int i = pool->queue_tail; i != pos;
i = (i - 1 + MAX_TASKS) % MAX_TASKS) {
pool->task_queue[i] = pool->task_queue[(i - 1 + MAX_TASKS) % MAX_TASKS];
}
// 插入新任务
pool->task_queue[pos] = task;
pool->queue_tail = (pool->queue_tail + 1) % MAX_TASKS;
pool->queue_size++;
pthread_cond_signal(&pool->queue_not_empty);
pthread_mutex_unlock(&pool->queue_lock);
printf("Task %d added to queue (priority: %d)\n", task.task_id, priority);
return task.task_id;
}
// 任务调度器
void* task_scheduler(void *arg) {
process_pool_t *pool = (process_pool_t *)arg;
while (!pool->shutdown) {
pthread_mutex_lock(&pool->queue_lock);
// 等待队列非空
while (pool->queue_size == 0 && !pool->shutdown) {
pthread_cond_wait(&pool->queue_not_empty, &pool->queue_lock);
}
if (pool->shutdown) {
pthread_mutex_unlock(&pool->queue_lock);
break;
}
// 获取任务
task_t task = pool->task_queue[pool->queue_head];
pool->queue_head = (pool->queue_head + 1) % MAX_TASKS;
pool->queue_size--;
pthread_mutex_unlock(&pool->queue_lock);
// 寻找空闲工作进程
int worker_id = find_idle_worker(pool);
if (worker_id >= 0) {
dispatch_task_to_worker(pool, worker_id, &task);
} else {
// 无空闲进程,等待
printf("No idle workers, waiting...\n");
sleep(1);
// 重新加入队列
process_pool_add_task(pool, task.task_func,
task.task_data, task.priority);
}
}
return NULL;
}
// 寻找空闲工作进程
int find_idle_worker(process_pool_t *pool) {
for (int i = 0; i < pool->worker_count; i++) {
if (!pool->workers[i].is_busy) {
return i;
}
}
return -1;
}
// 分发任务到工作进程
void dispatch_task_to_worker(process_pool_t *pool,
int worker_id, task_t *task) {
pool->workers[worker_id].is_busy = 1;
// 通过管道发送任务给工作进程
if (write(pool->workers[worker_id].pipefd[1], task, sizeof(*task)) == -1) {
perror("write to worker failed");
pool->workers[worker_id].is_busy = 0;
} else {
printf("Task %d dispatched to worker %d\n",
task->task_id, worker_id);
}
}
```
### 进程池监控与回收
```c
// 监控工作进程状态
void* monitor_workers(void *arg) {
process_pool_t *pool = (process_pool_t *)arg;
struct epoll_event events[MAX_PROCESSES];
// 创建epoll实例
int epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
perror("epoll_create1 failed");
return NULL;
}
// 添加所有工作进程管道到epoll
for (int i = 0; i < pool->worker_count; i++) {
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = pool->workers[i].pipefd[0];
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD,
pool->workers[i].pipefd[0], &ev) == -1) {
perror("epoll_ctl failed");
}
}
// 监控循环
while (!pool->shutdown) {
int nfds = epoll_wait(epoll_fd, events, MAX_PROCESSES, 1000);
for (int i = 0; i < nfds; i++) {
// 查找对应的worker
for (int j = 0; j < pool->worker_count; j++) {
if (pool->workers[j].pipefd[0] == events[i].data.fd) {
task_result_t result;
ssize_t bytes = read(events[i].data.fd,
&result, sizeof(result));
if (bytes > 0) {
pool->workers[j].is_busy = 0;
pool->workers[j].task_count++;
printf("Worker %d completed task %d (status: %d)\n",
result.worker_id, result.task_id, result.status);
} else if (bytes == 0) {
// 管道关闭,工作进程退出
printf("Worker %d pipe closed\n", j);
restart_worker(pool, j);
}
break;
}
}
}
}
close(epoll_fd);
return NULL;
}
// 重启工作进程
void restart_worker(process_pool_t *pool, int worker_id) {
pid_t old_pid = pool->workers[worker_id].pid;
// 创建新管道
int new_pipefd[2];
if (pipe(new_pipefd) == -1) {
perror("pipe creation failed");
return;
}
<"sdn.h4k7.org.cn"><"djh.h4k7.org.cn"><"ovo.h4k7.org.cn">
pid_t pid = fork();
if (pid == -1) {
perror("fork failed");
close(new_pipefd[0]);
close(new_pipefd[1]);
return;
}
if (pid == 0) {
// 新工作进程
close(new_pipefd[0]);
close(pool->workers[worker_id].pipefd[0]); // 关闭旧管道
worker_process(new_pipefd[1], worker_id);
exit(0);
} else {
// 主进程
close(new_pipefd[1]); // 关闭写端
close(pool->workers[worker_id].pipefd[0]); // 关闭旧管道
pool->workers[worker_id].pid = pid;
pool->workers[worker_id].pipefd[0] = new_pipefd[0]; // 更新读端
pool->workers[worker_id].is_busy = 0;
printf("Worker %d restarted (new PID: %d)\n", worker_id, pid);
}
}
```
### 进程池关闭与清理
```c
// 优雅关闭进程池
void process_pool_shutdown(process_pool_t *pool) {
if (!pool) return;
printf("Shutting down process pool...\n");
pool->shutdown = 1;
// 发送关闭信号给所有工作进程
for (int i = 0; i < pool->worker_count; i++) {
if (pool->workers[i].pid > 0) {
kill(pool->workers[i].pid, SIGTERM);
// 等待进程结束
int status;
waitpid(pool->workers[i].pid, &status, 0);
printf("Worker %d (PID: %d) terminated\n",
i, pool->workers[i].pid);
}
// 关闭管道
if (pool->workers[i].pipefd[0] > 0) {
close(pool->workers[i].pipefd[0]);
}
}
// 清理同步原语
pthread_mutex_destroy(&pool->queue_lock);
pthread_cond_destroy(&pool->queue_not_empty);
free(pool);
printf("Process pool shutdown complete\n");
}
// 获取进程池统计信息
void get_process_pool_stats(process_pool_t *pool) {
printf("\n=== Process Pool Statistics ===\n");
printf("Total workers: %d\n", pool->worker_count);
printf("Alive workers: %d\n", pool->alive_count);
printf("Tasks in queue: %d\n", pool->queue_size);
printf("\nWorker details:\n");
for (int i = 0; i < pool->worker_count; i++) {
printf(" Worker %d: PID=%d, Busy=%d, Tasks=%d\n",
i, pool->workers[i].pid,
pool->workers[i].is_busy,
pool->workers[i].task_count);
}
}
```
## 综合应用示例
```c
// 示例任务函数
void sample_task_1(void *data) {
int *value = (int *)data;
printf("Task 1 processing value: %d\n", *value);
// 模拟处理时间
sleep(1);
*value *= 2;
printf("Task 1 completed, new value: %d\n", *value);
}
void sample_task_2(void *data) {
char *text = (char *)data;
printf("Task 2 processing text: %s\n", text);
sleep(2);
// 处理文本
for (int i = 0; text[i]; i++) {
if (islower(text[i])) text[i] = toupper(text[i]);
}
printf("Task 2 completed, result: %s\n", text);
}
// 综合示例主函数
int main() {
printf("=== Process Communication Demo ===\n\n");
// 1. 匿名管道演示
printf("1. Anonymous Pipe Demo:\n");
anonymous_pipe_demo();
printf("\n");
// 2. 命名管道演示
printf("2. Named Pipe (FIFO) Demo:\n");
const char *fifo_path = "/tmp/my_fifo";
create_named_pipe(fifo_path);
// 在子进程中运行写入者
if (fork() == 0) {
fifo_writer(fifo_path);
exit(0);
}
// 在主进程中运行读取者
fifo_reader(fifo_path);
wait(NULL); // 等待子进程结束
unlink(fifo_path); // 清理FIFO文件
printf("\n");
// 3. 进程池演示
printf("3. Process Pool Demo:\n");
process_pool_t *pool = process_pool_init(4);
if (!pool) {
fprintf(stderr, "Failed to create process pool\n");
return 1;
}
// 创建调度器和监控器线程
pthread_t scheduler_thread, monitor_thread;
pthread_create(&scheduler_thread, NULL, task_scheduler, pool);
pthread_create(&monitor_thread, NULL, monitor_workers, pool);
// 添加示例任务
int value1 = 10;
char text1[] = "hello world";
int value2 = 20;
char text2[] = "process pool";
process_pool_add_task(pool, sample_task_1, &value1, 1);
process_pool_add_task(pool, sample_task_2, text1, 2);
process_pool_add_task(pool, sample_task_1, &value2, 3);
process_pool_add_task(pool, sample_task_2, text2, 4);
// 等待任务完成
sleep(5);
// 显示统计信息
get_process_pool_stats(pool);
// 关闭进程池
process_pool_shutdown(pool);
// 等待线程结束
pthread_join(scheduler_thread, NULL);
pthread_join(monitor_thread, NULL);
printf("\n=== All demos completed ===\n");
return 0;
}
```
## 性能优化与最佳实践
### 优化管道性能
```c
// 批量数据传输优化
void optimized_pipe_transfer(int pipefd, void *data, size_t size) {
// 设置管道为非阻塞
int flags = fcntl(pipefd, F_GETFL);
fcntl(pipefd, F_SETFL, flags | O_NONBLOCK);
size_t total_written = 0;
while (total_written < size) {
ssize_t written = write(pipefd, (char *)data + total_written,
size - total_written);
if (written == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 管道满,等待
struct pollfd pfd = {pipefd, POLLOUT, 0};
poll(&pfd, 1, -1);
continue;
} else {
perror("write failed");
break;
}
}
total_written += written;
}
// 恢复阻塞模式
fcntl(pipefd, F_SETFL, flags);
}
```
### 进程池容量规划
```c
// 自适应进程池大小调整
void adaptive_pool_scaling(process_pool_t *pool) {
// 监控负载并调整工作进程数量
int avg_load = calculate_average_load(pool);
int optimal_workers = calculate_optimal_workers();
if (avg_load > 80 && pool->worker_count < MAX_PROCESSES) {
// 增加工作进程
add_worker_to_pool(pool);
} else if (avg_load < 20 && pool->worker_count > 1) {
// 减少工作进程
remove_worker_from_pool(pool);
}
}
// 计算平均负载
int calculate_average_load(process_pool_t *pool) {
int busy_count = 0;
for (int i = 0; i < pool->worker_count; i++) {
if (pool->workers[i].is_busy) busy_count++;
}
return (busy_count * 100) / pool->worker_count;
}
```
## 总结
通过本文的详细解析,我们可以看到Linux进程通信从简单的管道到复杂的进程池实现的完整演进过程。关键要点包括:
1. **匿名管道**:适用于有亲缘关系的进程,简单高效
2. **命名管道**:适用于任意进程通信,基于文件系统
3. **进程池**:提高系统吞吐量和资源利用率,适合高并发场景
每种技术都有其适用场景:
- 一次性简单通信:使用匿名管道
- 持久化进程通信:使用命名管道
- 高并发任务处理:使用进程池
实际开发中应综合考虑性能要求、系统复杂度、维护成本等因素,选择最合适的进程通信方案。掌握这些基础技术对于构建高效、稳定的Linux系统至关重要。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3110109/ ,如需转载,请注明出处,否则将追究法律责任。