基于管道的进程间通信代码分析
来源:互联网 发布:办公软件应用2003 编辑:程序博客网 时间:2024/05/16 12:20
#include "sys/types.h"#include "sys/file.h"#include "stdio.h"#include "unistd.h"#include "string.h"#include "stdlib.h"char r_buf[4]; //读缓冲char w_buf[4]; //写缓冲int pipe_fd[2];pid_t pid1, pid2, pid3, pid4;//pid_t的本质就是intint producer(int id);int consumer(int id);int main(int argc,char **argv){ if(pipe(pipe_fd)<0){ printf("pipe create error \n"); exit(-1); }else{ printf("pipe is created successfully!\n"); if((pid1=fork())==0) producer(1); if((pid2=fork())==0) producer(2); if((pid3=fork())==0) consumer(1); if((pid4=fork())==0) consumer(2); } close(pipe_fd[0]); //需要加上这两句 close(pipe_fd[1]); //否这会有读者或者写者永远等待 int i,pid,status; for(i=0;i<4;i++){ pid=wait(&status); } exit(0);}int producer(int id){ printf("producer %d is running!\n",id); close(pipe_fd[0]); for (int i = 0; i < 10; i++) { sleep(3); //执行挂起3秒 if(id==1) //生产者1 strcpy(w_buf,"aaa\0");//每次重新清空数组并写入 else //生产者2 strcpy(w_buf,"bbb\0"); if(write(pipe_fd[1],w_buf,4)==-1){ printf("write to pipe error\n"); break; }else{ printf("producer %d write %s to pipe\n",id, w_buf); } } close(pipe_fd[1]); printf("producer %d is over!\n",id); exit(id);//退出进程导致其不再执行后面的fork()函数}int consumer(int id){ close(pipe_fd[1]); printf("consumer %d is running!\n",id); if (id==1) //消费者1 strcpy(w_buf,"ccc\0"); else //消费者2 strcpy(w_buf,"ddd\0"); while(1)//忙等待 { sleep(1);//挂起1秒 strcpy(r_buf,"eee\0"); if(read(pipe_fd[0],r_buf,4)==0) break; printf("consumer %d get %s, while the w_buf is %s\n",id,r_buf,w_buf); } close(pipe_fd[0]); printf("consumer %d is over!\n", id); exit(id);//退出进程导致其不再执行后面的fork()函数}
pipe(pipe_fd)函数会建立管道,将文件描述词由参数pipe_fd数组返回。因为子进程复制了父进程的打开文件表,所以pipe()所建立的通信管道可被子进程继承,生产和消费进程可以通过对同一管道文件的读写进行通讯。
pipe_fd[0]为管道里的读取端。
pipe_fd[1]则为管道的写入端。
若成功则返回零,否则返回-1,错误原因存于errno中。
错误代码:
EMFILE 进程已用完文件描述词最大量。
ENFILE 系统已无文件描述词可用。
EFAULT 参数 filedes 数组地址不合法。
当管道中的数据被读取后,管道为空。一个随后的read()调用将默认的被阻塞,等待某些数据写入。若需要设置为非阻塞,则可做如下设置:
fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK);
fcntl(pipe_fd[1], F_SETFL, O_NONBLOCK);
有关fork()函数的详细讲解,请看http://blog.csdn.net/stephan14/article/details/42872087这篇文章。
关于wait()函数,如果父进程创建的子进程退出后,父进程不调用wait()函数回收子进程的结束信息,子进程就会变成僵尸进程,如果子进程变成僵尸进程,那么会造成以下两点问题:
1.它的进程标示符占据着,意味着海量的子进程会占据满进程表项,会使后来的进程无法fork。
2.它的内核栈无法被释放掉,因为在栈的最低端,有着thread_info结构,它包含着struct_task结构,这里包含着一些退出信息。
有关僵尸进程的介绍:
一个进程终止的方法很多,进程终止后有些信息对于父进程和内核还是很有用的,例如进程的ID号、进程的退出状态、进程运行的CPU时间等。因此进程在终止时,回收所有内核分配给它的内存、关闭它打开的所有文件等等,但是还会保留以上极少的信息,以供父进程使用。父进程可以使用 wait/waitpid 等系统调用来为子进程收拾,做一些收尾工作。
因此,一个僵尸进程产生的过程是:父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。子进程的状态变成EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息。在 wait 调用之后,僵尸进程就完全从内存中移除。因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中。
至于write与read函数:
ssize_t write (int fd, const void * buf, size_t count);
write()会把参数buf 所指的内存写入count 个字节到参数fd 所指的文件内. 当然, 文件读写位置也会随之移动。
如果顺利write()会返回实际写入的字节数. 当有错误发生时则返回-1, 错误代码存入errno 中.
错误代码:
EINTR 此调用被信号所中断.
EAGAIN 当使用不可阻断I/O 时 (O_NONBLOCK), 若无数据可读取则返回此值.
EADF 参数fd 非有效的文件描述词, 或该文件已关闭.
ssize_t read(int fd, void * buf, size_t count);
read()会把参数fd 所指的文件传送count 个字节到buf 指针所指的内存中. 若参数count 为0, 则read()不会有作用并返回0. 返回值为实际读取到的字节数, 如果返回0, 表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动.如果顺利 read()会返回实际读到的字节数, 最好能将返回值与参数count 作比较, 若返回的字节数比要求读取的字节数少, 则有可能读到了文件尾等。当有错误发生时则返回-1, 错误代码存入errno 中, 而文件读写位置则无法预期.
错误代码:
EINTR 此调用被信号所中断.
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK), 若无数据可读取则返回此值.
EBADF 参数fd 非有效的文件描述词, 或该文件已关闭.
- 基于管道的进程间通信代码分析
- Linux进程间的通信-基于有序文件(匿名管道)
- 进程间的通信:管道
- 进程间的通信:管道
- Linux进程间的通信--管道通信
- 进程间通信:管道及命名管道(代码实现)
- 进程间管道通信
- 进程间通信: 管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信-管道
- 1002. A+B for Polynomials (25)
- Java/android面试题
- 神奇的overflow:hidden及其背后的原理
- .NET工具篇(二)—GACUtil
- C的库函数
- 基于管道的进程间通信代码分析
- Developing for Android, II The Rules: Memory
- 【SQL Server技巧篇】如何使用Transact-SQL脚本语言导入Excel表
- 对于某种无法改变的习性,我感到一种宿命的无奈。
- 轻量级web server Tornado代码分析
- 程序员的量化交易之路(24)--Cointrader之RemoteEvent远程事件实体(11)
- Add Two Numbers 链表基本应用
- Longest Substring Without Repeating Characters
- 【leetcode c++】ZigZag Conversion