Linux编程---进程通信
Linux的通信方式主要有分类有下面几种:
-匿名管道和FIFO有名管道
-消息队列,信号量和共享存储
-套接字
.对于套接字的进程通信,我就留在套接字的文章中再写了.
一.管道
管道是最古老的进程通信机制了.提供进程间的单向通信.
1.创建管道
int pipe(int fdes[2]);
实际上管道通过参数返回读和写的两个文件描述符.相当于是打开了两个文件吧.但是这个文件是特殊的pipe文件.fdes[0]表示的是输入,fdes[2]表示的是输出.注意,这个函数只创建一个文件,而不是创建两个文件一个用来读,一个用来写.
管道创建调用成功,那么就返回0,否则返回-1,并设置errno错误条件.
如果向写文件描述符进行读,那么会生成一个SIGPIPE信号,并且当信号被阻塞是将以EPIPE错误失败.管道文件不允许文件定位,读和写操作都是顺序的,读从文件的开始处读,写则写至文件尾.
这么看似乎好像没有和别的进程关联起来.实际上,管道单独使用的话只是创建了两个文件而已,想要使用管道还得使用fork,exec,dup等函数来创建一个进程才能使用.
简答来说,对于创建的进程来说,其读写的文件是相反的.并且对于管道来说,其方向只能是单向的,所以如果你创建了新进程,两个进程至少要关闭一个文件描述符.
2.popen和pclose函数
这两个函数是C标准库中的两个函数.并且创建的方式也比系统调用方便.
FILE *popen(const char *command,const char *mode);
int pclose(FILE * stream);
第一个函数通过第一个参数,解析其命令建立一个新进程.过程就是先建立一个管道,然后派生一个子进程,调用exec启动一个shell程序执行command给出的命令.并立即返回一个管道对应的流指针.
mode的方式只能是”r”和”w”两种方式之一,但是不能两个一起,所以这和一般的文件模式是不同的.
这么来看,这个函数就比用上面的pipe系统调用方便得多.封装了包括fork,exec,dup等一系列调用~当然,这个函数相对自己调用pipe+fork+exec+close来说效率就要差一些了.
管道IO的原子性
实际上管道就是一片内存缓冲区.(我记得原来学的时候创建一个管道,然后在图形界面下把管道文件给删了,但是管道仍然正常使用).所以如果写入管道的数据块大小超过这片缓冲区的大小时,内核就要分几次写入了.如果是分批写的话,那么就很可能造成混乱了.试想如果A进程需要分3次写,在写完第二次的时候时间片到了,切换到另外一个进程也要往这个管道写内容,那么就可能导致内容产生混乱.(可以fork出多个子进程向同一个管道进行写操作给父进程数据).如果是一对一的关系就无所谓了,但是对于一对多就需要注意了.
管道缓冲区的大小由定义在头文件<limits.h>中的宏PIPE_BUF给出.在Linux系统中其值为4096.并且一旦写入PIPE_BUF个字节至管道后,进一步写管道的操作将阻塞直到有些字节已读出.