日志标签 ‘有名管道’

pipe和fifo二三事

2012年4月23日

1.管道是什么?

管道是一种只存在于内存的特殊文件,没有磁盘文件与之对应。管道是通过虚拟文件系统pipefs而实现的,pipefs与proc、sysfs等特殊文件系统一样,只存在于内存中。另外,管道只能用于半双工通信。

2.pipe()一个管道意味着什么?

pipe()在pipefs文件系统中创建一个新的索引节点,同时创建两个file对象,一个file对象用于读操作,一个file对象用于写操作。pipe()最终将两个file对象对应的文件描述符返回给用户态进程,也就是向pipe()中传递的fd数组。

3.子进程execv()后是否还能继续共享父进程的管道?

子进程execv()后,不能再继续使用父进程创建的管道,因为子进程当前的上下文已经完全被可执行文件替换。如果要继续使用管道,子进程可以在execv()之前将两个文件描述符重定向到标准输入和输出。

4.描述管道的数据结构与索引节点的关系?

管道虽然是一种特殊文件,它仍然通过VFS框架中的inode来描述。由于VFS要对所有不同的文件进行抽象描述,因此inode只对所有文件的共性进行描述。inode中的i_pipe字段指向pipe_inode_info结构,该结构用于描述管道的特性。

5.写管道时写入的字节量与管道大小的关系?

管道缓冲区通常为一个单独的页框,因此大小默认为4096字节。如果两个或者多个进程并发的写入一个管道,那么任何少于4096字节的写操作都是原子的。但是,如果向管道写入大于管道缓冲区大小的数据,则写操作是可以分割的,也就是说多个进程的写操作可以交叉进行,此时应该注意进程的同步。

6.有名管道是什么?

有名管道是一种设备文件,有对应的磁盘索引节点。因为存在于磁盘上,因此可以被任何进程打开使用。有名管道是一种半双工通信方式。

7.ls | more 的大致执行过程?

在终端执行ls | more时,shell进程fork()出一个进程A用来执行上述命令。A进程调用pipe(),返回文件描述符fd1和fd2,分别用于读和写管道。进程A两次调用fork(),产生两个子进程。进程A关闭fd1和fd2。

对于第一个子进程,它调用dup2(fd2,1)将写文件描述符重定向到标准输出。接下来调用execv()系统调用执行ls程序,该程序将自己的输出写入管道。

对于第二个子进程,它调用dup2(fd1,0)将读文件描述符重定向到标准输入。接下来调用execv()系统调用执行more程序,该程序从管道中读取数据。

IPC under Linux-FIFO(2)

2010年8月23日

下面我们来详细说明有名管道的读写规则。

3.有名管道读取规则

(1)如果进程A事先写打开FIFO,但却不进行写操作(FIFO中为空),那么进程B对其进行读操作时候将会阻塞,或者直接返回-1(当设置了非阻塞标志时)。
我们继续以《LinuxC编程实战》一书中的例子(P252)为原型,对procwrite.c函数稍作改动即可,具体代码如下。

	printf("Now the writer will sleep 5s..\n");
	sleep(5);
	printf("Now the writer wake up and will write to FIFO..\n");
	write(fd,buf,strlen(buf)+1);
	printf("writer will leave!\n");
	close(fd);

我们可以发现,procwrite进程运行后,发生了阻塞,这一点可用上文的打开规则来解释。当在另一个终端运行procread进程后,此时的procwrite正常运行。由于我们让procwrite进程睡眠5s,所以当前管道缓冲区是空的,我们可以在另一终端发现procread进程发生了阻塞。但当procwrite睡眠结束,继续运行时,procread进程可正确读出管道内数据。

如果你理解了规则1,那么我们继续来了解两种读操作阻塞的情况。

(2)当FIFO中有数据时,但是正在被进程A所读取,如果B进程此时也欲读FIFO,B进程将阻塞;如果FIFO中无数据,那么读进程也将阻塞(规则1所述)。想要解除阻塞只要在管道内写入数据即可,不管写入多少数据,也不管读进程请求读多少数据。

我们继续以上述例子为原型,但是需要两个读进程。首先procwrite进程先进行第一次写,然后睡眠20s,接着进行第二次写操作,这是为了解除因读操作而阻塞的进程。

        //procwrite.c部分代码
	printf("Now the writer will write data to FIFO..\n");
	write(fd,buf,strlen(buf)+1);
	printf("writer will leave!\n");
	sleep(20);
	strcpy(buf,"The write write another data now");
	write(fd,buf,strlen(buf)+1);
	close(fd);
	exit(0);

在procread.c程序中,我们让此进程一次性只读取一个字符。

int n=20;
while(n--)
{
read(fd,buf,1);
buf[strlen(buf)]='\0';
printf("Read content:%s\n",buf);
sleep(2);
}
close(fd);
unlink(FIFO_NAME);
exit(0);

在procread2.c程序中,我们让此进程一次性读完管道内所有数据。

printf("I will read data from FIFO..\n");
read(fd,buf,BUF_SIZE);
printf("Read content:%s\n",buf);
close(fd);
exit(0);

我们首先运行procwrite,然后立马运行procread,可以看到其每次只输出一个字符;接着我们运行procread2,可以看到这个进程一次性读完了管道内剩余的所有数据,而此时再看运行procread的那个终端,可知procread进程发生了阻塞,不过再稍等片刻,可发现它有接着输出字符,这是因为procwrite进程第二次的写操作解除了procread进程的阻塞。

这里只是为大家做一个简单的演示,我们可以在理解上述规则的基础上编写其他程序去验证。

4.有名管道的写规则

如果打开FIFO时,没有加非阻塞标志,那么写操作遵循以下的规则:

(1)如果写入数据的字节数不大于PIPE_BUF(注意,从内核2.6.11开始,其值为65536),Linux将保证写操作的原子性。当管道内的剩余缓冲区大于要写入的数据字节数时,那么将一次性写完数据;否则,进程进入睡眠状态,直至管道内的缓冲区可以容纳要写入的数据为止。

(2)如果写入的数据字节数不大于PIPE_BUF,那么Linux将不保证写操作的原子性。管道内一有空闲的缓冲区,写进程就去写数据,直至所有数据都被写完为止。

如果打开FIFO的时候加入了阻塞标志,那么写操作遵循一下规则:

(1)如果要写入数据的字节数大于PIPE_BUF,那么linux将不会保证写入的原子性。在写满所有FIFO空闲缓冲区后,写操作返回。

(2)如果要写入的数据的字节数不大于PIPE_BUF,那么linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写。

IPC under Linux-FIFO(1)

2010年8月20日

上文中我们了解了管道这个基本的通信方式,不过在文章最后我们也总结了管道的相关局限性,比如仅可以在亲缘进程之间进行通信等。本文要说明的IPC通信方式实际上可称作PIPE的加强版:有名管道(FIFO或者named PIPE)。首先“望文思意”,FIFO是具有具体文件名的(具体路径名),因为FIFO是一个设备文件。因此,对于一般文件的操作,比如open,write,read都可以对有名管道进行操作。

1.创建有名管道

使用mkfifo函数就可以了,但是并不会类似PIPE那样:先fork,再mkfifo。还记得吗,任意进程间都可以进行FIFO通信,因此在A程序(进程)中创建了管道,在B程序(进程)中只要打开相应的管道即可。

2.有名管道的打开规则

当我们创建了有名管道时,每次使用前还要用open函数打开这个管道文件。其实这并不是有名管道的什么特殊之处,因为有名管道是存在于磁盘上的文件,而管道是存在内存中的特殊文件。

这里我们需要注意的是,进程以不同的方式打开有名管道,会对其自身产生不同的影响。下面我们一点一点的去了解。

首先,如果进程以O_RDWR方式打开管道,此进程一定不会阻塞。

如果进程A以只写方式打开管道,那么这个进程会一直阻塞到有另外一个进程B以写方式打开管道为止。当然,如果A进程以只读方式打开管道前,B进程就已经以只写方式打开了管道,那么A进程必然不会阻塞。

类似的,如果A进程以只写方式打开管道,而没有其他进程以读方式打开管道,那么A进程也会阻塞。

上面我们所说的规则具有一般性,因为缺省情况下进程是以阻塞方式打开文件的。如果我们打开管道时加入了非阻塞标志(O_NONBLOCK),那么又会产生和上面不一样的情况。具体如下问所述。

如果进程A以只写方式打开管道,此时又无其他进程以只读方式打开管道,那么进程A将返回错误标志ENXIO。进程A以只读方式打开管道的情况与上类似。

如何去验证上述打开规则?《LinuxC编程实战》一书中例10-5就是个很好的验证程序。

如果按照此书所述那样去运行程序,可以发现procwrite会在procread运行前阻塞。如果我们在procwrite.c中以可读写方式打开管道,那么可以发现运行procwrite后立马会运行完毕。而且,我们ls -l一下,可以发现当前目录下多了一个myfifo的管道文件(注意文件存取权限最前面的那个P)。

关于打开规则更多的测试,请参考这里的例子:附录2,对我们的理解有极大帮助。

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key