一、需求
现有两个进程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;
}
五、总结
注意使用管道时的阻塞情况。