目录
无名管道
无名管道
无名管道是半双工的,就是对于一个管道来讲,只能读,或者写。
无名管道只能在相关的、有共同祖先的进程间使用。
一个fork或者exec调用创建的子进程继承了父进程的文件描述符。
打开和关闭管道
int pipe(int filedes[2]);
在你从一个管道中读出或者写入数据,这个管道必须存在。
如果成功建立了管道,则会打开两个文件描述符,并把它们的值保存在一个整数数组中。
第一个文件描述符用于读取数据,第二个文件描述符用于写入数据。
如果出错返回-1,同时设置errno 关闭一个管道用close()函数
读写管道
读写管道与读写普通文件方式一样,调用write与read函数即可。
几乎不会在一个进程中打开一个管道仅供进程自己使用,管道是用来交换数据的。
因为一个进程已经能够访问它要通过管道共享的数据,和自己共享数据是没有意义的。
试图对一个管道的两端进行读写操作是一个严重的错误。
读写无名管道示例
int main(int arg, char * args[])
{
int fd[2];char buf[100];int len;
pipe(fd);
memset(buf, 0, sizeof(buf));
int pid = fork();
if (pid == 0)
{
close(fd[1]);
while((len = read(fd[0], buf, sizeof(buf))) >0)
{
write(STDOUT_FILENO, buf, len);
}
close(fd[0]);
}
else
{
close(fd[0]);
strcpy(buf, "hello world\n");
write(fd[1], buf, sizeof(buf));
close(fd[1]);
waitpid(pid, NULL, 0);
}
return 0;
}
有名管道(FIFO)
有名管道是持久稳定的。 它们存在于文件系统中
FIFO比无名管道作用更大,因为它们能让无关联的进程之间交换数据
shell命令可以建立有名管道
mkfifo [option] name
mkfifo创建一个名为name的有名管道
mkfifo fifo1。 创建一个有名管道fifo1。
cat < fifo1。 通过cat命令从fifo1中读取数据。
ls > fifo1。 将ls命令输出的结果写入fifo1中
方法创建fifo
int mkfifo(const char *pathname, mode_t mode)
函数执行成功返回0,否则返回-1,并设置变量errno。
mkfifo函数示例
int main(int arg, char *args[])
{
mkfifo("fifo1", 0666);
return 0;
}
八进制数0666转化为二进制后为110110110,代表读写权限为rw-rw-rw-
删除fifo
int unlink(const char *pathname);
函数执行成功返回0,否则返回-1,并设置变量errno。
unlink函数示例
int main(int arg, char * args[])
{
int i = unlink("fifo1");
if (i == -1)
{
printf(strerror(errno));
}
return 0;
}
打开和关闭FIFO
int open(const char *pathname, int flags); int close(int fd);
Linux的一切都是文件这一抽象概念的优势,打开和关闭FIFO和打开关闭一个普通文件操作是一样的。
FIFO的两端使用前都必须要打开。
open中如果参数flags为O_RDONLY将阻塞open调用,一直到另一个进程为写入数据打开FIFO为止。相同的,O_WRONLY也导致阻塞一直到为读出数据打开FIFO为止
读FIFO例子
int main(int arg, char * args[])
{
int len = 0;
char buf[100];
memset(buf, 0, sizeof(buf));
int fd = open("fifo1", O_RDONLY);
while ((len = read(fd, buf, sizeof(buf))) > 0)
{
printf("%s\n", buf);
}
close(fd);
return 0;
}
写FIFO例子
int main(int arg, char * args[])
{
int len = 0;
char buf[100];
memset(buf, 0, sizeof(buf));
int fd = open("fifo1", O_WRONLY);
while(1)
{
scanf("%s", buf);
if (buf[0] == '0')
break;
write(fd, buf, sizeof(buf));
}
close(fd);
return 0;
}
mmap映射
映射关系可以分为两种
1、文件映射
磁盘文件映射进程的虚拟地址空间,使用文件内容初始化物理内存。
2、匿名映射
初始化全为0的内存空间
而对于映射关系是否共享又分为
1、私有映射(MAP_PRIVATE)
多进程间数据共享,修改不反应到磁盘实际文件,是一个copy-on-write(写时复制)的映射方式。
2、共享映射(MAP_SHARED)
多进程间数据共享,修改反应到磁盘实际文件中
总结起来有4种组合
1、私有文件映射
多个进程使用同样的物理内存页进行初始化,但是各个进程对内存文件的修改不会共享,也不会反应到物理文件中
2、私有匿名映射
mmap会创建一个新的映射,各个进程不共享,这种使用主要用于分配内存(malloc分配大内存会调用mmap)。
例如开辟新进程时,会为每个进程分配虚拟的地址空间,这些虚拟地址映射的物理内存空间各个进程间读的时候共享,写的时候会copy-on-write。
3、共享文件映射
多个进程通过虚拟内存技术共享同样的物理内存空间,对内存文件 的修改会反应到实际物理文件中,他也是进程间通信(IPC)的一种机制。
4、共享匿名映射
这种机制在进行fork的时候不会采用写时复制,父子进程完全共享同样的物理内存页,这也就实现了父子进程通信(IPC)