ITPub博客

首页 > 应用开发 > IT综合 > 进程通信实战:从管道到进程池的完整实现

进程通信实战:从管道到进程池的完整实现

翻译 IT综合 作者:bhluo 时间:2026-02-06 13:57:42 0 删除 编辑

# 进程通信实战:从管道到进程池的完整实现


在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/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    933808