Last Updated: 2023-11-05 08:21:23 Sunday
-- TOC --
所谓命名管道,就是这个管道在文件系统中,有一个pathname,还有对应的权限,它是一个特殊的文件。
mkfifo是一个shell命令,同时也是一个glibc提供的C编程接口,功能相同,参考man 3 mkfifo
。fifo表示first in first out,先进先出,这就是pipe的属性。
// mkfifo - make a FIFO special file (a named pipe)
// man 3 mkfifo
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
mkfifo底层可能是系统调用mknod
:man 2 mknod
。mknod调用的第3个参数填0,就是创建named fifo pipe(未测试),否则第3个参数就要设备文件的major和minor。
下面是一段测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#define _PEXIT \
do {\
char ebuf[64] = {0};\
sprintf(ebuf, "%s: %d", __FILE__, __LINE__);\
perror(ebuf);\
exit(errno);\
}while(0)
void ptime(void) {
time_t now;
time(&now);
printf("%ld ", now);
}
int main(int argc, char *argv[]) {
assert(argc == 2);
/* 0777 & ~umask */
if (mkfifo(argv[1], 0777) != 0)
_PEXIT;
ptime();
printf("mkfifo ok\n");
/* fork a child to read */
pid_t child;
child = fork();
if (child == 0) {
/* in child */
sleep(3);
int fd;
if ((fd=open(argv[1], O_RDONLY)) < 0)
_PEXIT;
/* read */
char rb[64] = {0};
if (read(fd,rb,64) < 0)
_PEXIT;
close(fd);
ptime();
printf("%s (child)\n", rb);
exit(0);
}
/* open in write only mode, block if no open in read */
int fd;
if ((fd=open(argv[1], O_WRONLY)) < 0)
_PEXIT;
ptime();
printf("open ok\n");
/* in parent, write immediately */
char *wb = "hello mkfifo";
if (write(fd,wb,strlen(wb)) < 0)
_PEXIT;
close(fd);
ptime();
printf("write on\n");
wait(NULL);
/* delete */
if (remove(argv[1]) != 0)
_PEXIT;
return 0;
}
刻意在子进程中先等3秒钟,这是为了测试一个效果:如果以写的方式打开named pipe,此时还没有以读方式打开的fd,写方式的open会block,直到有以read方式open的代码执行。
匿名管道在创建的时候,读写fd都有了,因此不存在这个block的问题。
测试如下:
$ ./test_mkfifo np1
1658484053 mkfifo ok
1658484056 open ok
1658484056 write on
1658484056 hello mkfifo (child)
重复创建相同名称的fifo文件时,会出错,因此代码最后调用了remove。
本文链接:https://cs.pynote.net/sf/linux/prog/202202105/
-- EOF --
-- MORE --