设计思路
- 命名管道读写性能优化:
- 使用非阻塞I/O模式,避免读写操作的阻塞,从而可以在同一时间内处理多个管道的读写。可以使用
fcntl
函数设置管道文件描述符为非阻塞模式。
- 采用较大的缓冲区,减少系统调用次数。每次读写尽量传输较大的数据块,提高数据传输效率。
- 动态管理多个命名管道:
- 使用链表来管理命名管道的相关信息,每个节点存储管道的路径、文件描述符等信息。
- 提供创建、删除管道的函数,当有新的进程需要通信时,可以动态创建新的命名管道,并将其信息加入链表;当进程结束不再需要通信时,删除对应的管道并从链表中移除相关信息。
- 进程异常终止感知与恢复:
- 使用信号机制,当某个进程异常终止时,操作系统会发送相应的信号(如
SIGCHLD
)给其父进程或相关进程组。
- 在接收信号的处理函数中,遍历命名管道链表,检查哪些管道对应的进程可能出现异常,并进行相应的恢复操作,如关闭异常进程对应的管道,重新创建管道并尝试重新连接其他进程。
关键代码片段
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFFER_SIZE 1024
// 命名管道链表节点结构
typedef struct PipeNode {
char path[256];
int fd;
struct PipeNode *next;
} PipeNode;
// 链表头指针
PipeNode *pipeList = NULL;
// 创建命名管道并加入链表
void createPipe(const char *path) {
if (mkfifo(path, 0666) == -1 && errno != EEXIST) {
perror("mkfifo");
return;
}
PipeNode *newNode = (PipeNode *)malloc(sizeof(PipeNode));
if (newNode == NULL) {
perror("malloc");
return;
}
strcpy(newNode->path, path);
newNode->fd = -1;
newNode->next = pipeList;
pipeList = newNode;
}
// 删除命名管道并从链表移除
void deletePipe(const char *path) {
PipeNode *prev = NULL;
PipeNode *curr = pipeList;
while (curr != NULL && strcmp(curr->path, path) != 0) {
prev = curr;
curr = curr->next;
}
if (curr == NULL) {
return;
}
if (curr->fd != -1) {
close(curr->fd);
}
unlink(curr->path);
if (prev == NULL) {
pipeList = curr->next;
} else {
prev->next = curr->next;
}
free(curr);
}
// 信号处理函数
void sigchldHandler(int signum) {
// 这里可以遍历pipeList,检查异常终止进程对应的管道并处理
// 例如关闭相关管道,重新创建等操作
printf("Caught SIGCHLD, handling process termination...\n");
}
int main() {
// 设置信号处理函数
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigchldHandler;
sigaction(SIGCHLD, &sa, NULL);
// 创建命名管道示例
createPipe("/tmp/pipe1");
createPipe("/tmp/pipe2");
// 以非阻塞模式打开管道示例
PipeNode *curr = pipeList;
while (curr != NULL) {
curr->fd = open(curr->path, O_RDWR | O_NONBLOCK);
if (curr->fd == -1) {
perror("open");
}
curr = curr->next;
}
// 读写操作示例
char buffer[BUFFER_SIZE];
curr = pipeList;
while (curr != NULL) {
ssize_t bytesRead = read(curr->fd, buffer, BUFFER_SIZE);
if (bytesRead > 0) {
buffer[bytesRead] = '\0';
printf("Read from %s: %s\n", curr->path, buffer);
}
ssize_t bytesWritten = write(curr->fd, "Hello, Pipe!", strlen("Hello, Pipe!"));
if (bytesWritten == -1) {
perror("write");
}
curr = curr->next;
}
// 删除命名管道示例
deletePipe("/tmp/pipe1");
deletePipe("/tmp/pipe2");
return 0;
}