一、需求
现有两个进程A和B,B进程含较为独立且复杂的业务逻辑,A进程为主控进程,现A进程需要控制B进程执行对应的功能,且要保持响应及时。
二、分析
典型进程间通信案例,因此使用linux下的管道方法(pipe)。由于是无父子关系的两个进程的通信,因此使用命名管道,如是具有父子关系的进程,使用匿名管道。
三、操作
3.1管道初始化
// 创建管道文件mkfifo(PIPE_NAME, 0777);
其中,参数1为需要创建的管道文件路径与名称,参数2为文件权限。
3.2管道打开
fd = open(PIPE_NAME, O_WRONLY);// 打开管道文件if (fd < 0){printf("pipein: exit{open file failed}\n");perror("open");exit(1);}
注意,此时处于管道的输入进程(pipein),即A进程,此时如B进程还未启动,则程序会阻塞在open函数中,等待B进程打开管道。(重点:pipe管道在open中的现象为卡住、阻塞住)
仅在A进程中打开管道的现象:
当B进程启动后打开管道后的现象:
可以看到管道顺利流通。
也因此,为避免阻塞A进程的其他功能,会使用fork()创建子进程来进入阻塞等待B进程启动完成。
3.3管道写入
// 写入数据printf("pipein: write msg=%d\n", time);sprintf(buffer, "%d\n", time);write(fd, buffer, sizeof(buffer));sleep(1);
同写文件操作一致。
3.4管道读取
// 读取数据read(fd, buffer, sizeof(buffer));printf("pipeout: read msg=%s", buffer);sleep(1);
3.5管道释放
// 删除管道文件unlink(PIPE_NAME);
如不执行删除操作,管道文件会一直存在,且可以被继续使用。
四、源码
4.1 pipein.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#define BUFFER_SIZE 256#define PIPE_NAME "/mnt/UDISK/q2j"int main(){int fd;char buffer[BUFFER_SIZE];pid_t pid;// 创建管道文件mkfifo(PIPE_NAME, 0777);printf("pipein: create mkfifo successed\n");fd = open(PIPE_NAME, O_WRONLY);// 打开管道文件if (fd < 0){printf("pipein: exit{open file failed}\n");perror("open");exit(1);}printf("pipein: opening pipe\n");int time = 0;while (1){time++;// 写入数据printf("pipein: write msg=%d\n", time);sprintf(buffer, "%d\n", time);write(fd, buffer, sizeof(buffer));sleep(1);}// 关闭文件close(fd);}
4.2 pipeout.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#define BUFFER_SIZE 256#define PIPE_NAME "/mnt/UDISK/q2j"int main(){int fd;char buffer[BUFFER_SIZE];pid_t pid;printf("pipeout: init successed\n");// 打开管道文件if ((fd = open(PIPE_NAME, O_RDONLY)) < 0){perror("open");exit(1);}while (1){// 读取数据read(fd, buffer, sizeof(buffer));printf("pipeout: read msg=%s", buffer);sleep(1);}// 关闭文件close(fd);// 删除管道文件unlink(PIPE_NAME);return 0;}
五、总结
注意使用管道时的阻塞情况。