您的位置:首页 > 运维架构 > Linux

linux进程间通信方式之匿名管道

2009-10-23 21:47 561 查看
linux的进程间通信方式主要有:匿名管道、有名管道、消息队列、共享内存、信号、信号量及信号灯、socket网络通信。近日由于项目需要,用linux编写arm的应用程序,里面有几个功能模块,若干进程,进程间的通信方式选择了管道、共享内存和信号量的配合。这几天终于把程序的框架搭建好了,而我也对管道通信有了进一步的认识。

匿名管道只能用于具有亲缘关系,如父子、兄弟这样的进程间通信。创建方式

#include <unistd.h>

int pipe(int fd[2]) ;

fd为文件描述符数组,数组的两个元素是管道的读写文件描述符,fd[0]是管道读出端,fd[1]是管道的写入端。

创建成功返回0,失败返回-1 并设置全局变量error

匿名管道使用实例

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

int main(int argc,char* argv[])

{

int fd[2];

char buff[100];

if(pipe(fd)==-1){

perror("failed pipe");

exit(1);

}

if( !fork()){ /*创建写子进程*/

while(1){

printf("write process/n");

write(fd[1],"hello world/n",13);

sleep(1);

}

}

else{ sleep(1); /*父进程是读进程*/

while(1){

read(fd[0],buff,sizeof(buff) );

printf("read process/n");

printf("receive:%s/n",buff);

sleep(1);

}

}

return 0;

}

程序运行结果:

[root@gylinux test_pipe]# make

gcc -c -o main.o main.c

gcc -o test_pipe main.o

[root@gylinux test_pipe]# ./test_pipe

write process

write process

read process

receive:hello world

write process

read process

receive:hello world

源程序中若设置不同长度的休眠时间,比如写进程休眠时间为5秒,则读进程在读时由于管道是空,发生阻塞,读进程也休眠;若写进程休眠为5秒,写进程不会阻塞,而是一直写入数据。试将程序修改为如下:

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

int main(int argc,char* argv[])

{

int fd[2];

char buff[15];

if(pipe(fd)==-1){

perror("failed pipe");

exit(1);

}

int i=5,nt;

char data[]=" :hello world/n";

if( !fork()){ /*创建写子进程*/

while(i){

printf("%d:write process/n",i);

data[0]=i+'0';

i--;

nt=write(fd[1],data,15);

if(nt==-1){/*添加对写入文件成功与否的判断*/

perror("write error");

}

else printf("write size:%d/n",nt);

//sleep(1);

}

}

else{ sleep(1); /*父进程是读进程*/

while(1){

read(fd[0],buff,sizeof(buff) );

printf("read process/n");

printf("receive:%s/n",buff);

//sleep(1);

}

}

return 0;

}

程序运行结果:

5:write process

write size:15

4:write process

write size:15

3:write process

write size:15

2:write process

write size:15

1:write process

write size:15

read process

receive:5:hello world

这时写进程连续写入5次,读进程只显示了第一次的内容,这是因为读进程的缓冲区为100,一次就将5次的写入都读出了,并清空管道缓冲区。而printf函数只能显示'/0' 前面的内容,即第一次。

如果把读进程缓冲区大小设置为15,再试一次,程序如下:

int main(int argc,char* argv[])

{

int fd[2];

char buff[15]; /*这里改为15*/

if(pipe(fd)==-1){

perror("failed pipe");

exit(1);

}

int i=5,nt;

char data[]=" :hello world/n";

if( !fork()){ /*创建写子进程*/

while(i){

printf("%d:write process/n",i);

data[0]=i+'0';

i--;

nt=write(fd[1],data,15);

if(nt==-1){

perror("write error");

}

else printf("write size:%d/n",nt);

//sleep(1);

}

}

else{ sleep(1); /*父进程是读进程*/

while(1){

read(fd[0],buff,sizeof(buff) );

printf("read process/n");

printf("receive:%s/n",buff);

//sleep(1);

}

}

return 0;

}

运行结果:

5:write process

write size:15

4:write process

write size:15

3:write process

write size:15

2:write process

write size:15

1:write process

write size:15

read process

receive:5:hello world

read process

receive:4:hello world

read process

receive:3:hello world

read process

receive:2:hello world

read process

receive:1:hello world

可以看到,这时能够正常显示所有的发送数据,然后管道为空时,读进程进入阻塞态。

linux的每个管道空间有限,当管道满时,写进程将无法写入,而进入阻塞态。再做一个例子,实测管道空间大小:

int main(int argc,char* argv[])

{

int fd[2];

char buff[15];

if(pipe(fd)==-1){

perror("failed pipe");

exit(1);

}

int i=0,nt;

char data[1024]=" :hello world/n"; /*每次写入1K*/

if( !fork()){ /*创建写子进程*/

while(1){

printf("%d:write process/n",i);

data[0]=i+'0';

i++;

nt=write(fd[1],data,sizeof(data));

if(nt==-1){

perror("write error");

exit(1);

}

else printf("write size:%d/n",nt);

}

}

else{ sleep(1); /*父进程是读进程*/

while(1){

}

}

return 0;

}

这个例子的结果是

.......61:write process

write size:1024

62:write process

write size:1024

63:write process

write size:1024

64:write process

这个例子只写不读,程序写到第64次进入阻塞,说明缓冲区最大为64k,写满后进程阻塞。

修改data参数的长度,可以发现随每次写入的长度不同,但是最大缓冲始终为64k,小于64k的数据最少能写一次;如果把data长度修改为大于64k,则无法写入,但是进程进入阻塞态,并不报错。

通过这几个例子,可以得到结论:匿名管道在具有亲缘关系的进程通信中使用很方便。管道为空时读进程进入阻塞,管道数据满时写进程进入阻塞。管道最大的容量为64k,但是网上很多人说最大是4k,我想这可能与内核或者平台有关系。另外修改内核源代码,也可以改变管道容积。

实际使用中,一般都用自定义的数据结构体,使得每次写入和读出的数据长度一致,防止数据的丢失。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: