有名管道
有名管道是独立于进程存在的
有名管道可以看成是有文件名标识的一个管道,不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。FIFO一旦创建,open、write、read、close操作跟普通文件一样(不支持诸如lseek()等文件定位操作)。
创建管道
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
pathname:路径名
mode:权限模式
类似的命令:mkfifo -m 模式 文件名,如图
删除管道
int unlink(const char *pathname);
open/read/write/close这几个操作与普通文件的操作一样
阻塞/等待
读端:open(O_RDONLY) 写端:open(O_WRONLY)
注意:只有读端或者只有写端的时候,open函数都会阻塞
写端关闭:只剩下读端时,读端返回0
读端关闭:只剩下写端时,写端会被禁止
代码演示:
创建有名管道
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<stdlib.h>
int main()
{
if(mkfifo("myfifo", 0666) == -1)
{
perror("mkfifo");
exit(1);
}
return 0;
}
写管道
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#define N 64
int main()
{
int fd;
char *s;
char buf[N];
if((fd = open("myfifo", O_WRONLY)) == -1)
{
perror("open");
exit(1);
}
while((s = fgets(buf, N, stdin)))
{
write(fd, buf, sizeof(buf));
if(strncmp(buf, "quit", 4) == 0)
break;
}
close(fd);
return 0;
}
读管道
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#define N 64
int main()
{
int fd;
ssize_t n;
char buf[N];
if((fd = open("myfifo", O_RDWR)) == -1)
{
perror("open");
exit(1);
}
while(1)
{
if((n = read(fd, buf, N)) <= 0)
{
perror("read");
exit(1);
}
if(strncmp(buf, "quit", 4) == 0)
break;
printf("%s", buf);
}
close(fd);
return 0;
}
运行
注意:多个进程读fifo,有名管道是一个队列而不是一个普通文件,写端将字节写入队列,而读端从队列的头部移出字节,每个读端都会将数据移出队列,所以如果想保证读端都读到数据,写端必须要重写数据,看图
竞态:
FIFO不会出现竞态问题,read和write系统调用时原子操作。即读取操作将管道清空,而写入操作一次性将数据写入或者将管道塞满。在读端和写端连通之前,系统内核会将进程挂起。