12----进程间的通信:管道
来源:互联网 发布:游戏编程培训学费多少 编辑:程序博客网 时间:2024/05/09 08:37
一. IPC
1. 基于文件
1.1 无序文件
1.2 有序文件
管道:
有名
无名
socket
2. 基于内存
2.1 无序内存
2.1.1 匿名内存
2.1.2 共享内存
2.2 有序内存
2.2.1 消息队列
3. 同步:基于内存IPC应用(共享内存数组)
信号量/ 信号灯
二. 命名管道(FIFO)
命名管道是一种特殊类型的文件。
1.创建管道文件
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
案例:
(1)fifoA.c 文件
建立管道文件
打开管道文件
写数据
关闭管道文件
删除管道
(2) fifoB.c
打开管道
读数据
关闭管道
// fifoA.c#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <stdlib.h>#include <string.h>#include <signal.h>int fd;int i = 0;const char *filename = "/tmp/my.pipe";void deal(int s){// 3.关闭管道 close(fd);//4.删除管道unlink(filename);exit(0);}main(){signal(SIGINT,deal);//1. 建立管道mkfifo( filename,0666);//2. 打开管道fd = open(filename,O_RDWR);while(1){ // 每个1s写数据sleep(1);write(fd,&i,sizeof(4));++i;}}
// fifoB.c#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <sys/stat.h>#include <stdlib.h>#include <string.h>#include <signal.h>int fd;const char* filename = "/tmp/my.pipe";void deal(int s){// 关闭管道close(fd);exit(-1);}main(){int i;signal(SIGINT,deal);//建立管道mkfifo(filename,0666);// 打开管道fd = open(filename,O_RDWR);// 读取数据while(1){read(fd,&i,sizeof(i));printf("%d\n",i);}}
实例解析: 程序A循环发送数据,程序B循环接收数据。无论那个程序接收到中断信号(Ctrl + C),都会执行FIFO文件的删除工作。
总结:
(1)read没有数据,read就会阻塞,程序挂起。而read后数据是被删除的。
(2)数据有序。
(3)打开的描述符号可以读写(two-way 双工)
(4)管道文件关闭后,数据不持久。
(5)管道的数据存储在内核缓冲中。(可以说数据没有写入文件中)
三.匿名管道
有名管道的名字仅仅是内核,是否返回一个fd标识(zhi)符。
在父子进程之间: 打开文件描述符后创建进程。
父子进程都有文件描述符。管道文件名没有价值了。
所以在父子进程中引入一个没有名字的管道: 匿名管道。
结论: 匿名管道只能使用在父子进程之间。
1. 匿名管道的创建
#include <unistd.h>
int pipe(int pipefd[2]);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>
int pipe2(int pipefd[2], int flags);
fd[0]: 只读(不能写)
fd[1]: 只写(不能读)
案例: 匿名管道的创建。
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>int main(){int fd;int file_pipes[2];const char data[] ="自强不息,知行合一";char bufer[BUFSIZ + 1];memset(bufer,0,sizeof(bufer));if(pipe(file_pipes) == 0){if(fork() == 0) // child{ //sleep(1);fd = read(file_pipes[0],bufer,BUFSIZ);printf("Read %d bytes:%s\n",fd,bufer);exit(0);}else // fild{fd = write(file_pipes[1],data,strlen(data));printf("Wrot %d bytes\n",fd);}}exit(0);}
实验解析: 这个程序使用 pipe 函数创建一个管道,接着fork函数创建一个新进程。创建成功后,父进程写数据到管道中,而子进程从管道中读取数据。
综合案例:
(1)建立两个子进程:
一个负责计算: 1-50000 的素数
另一个负责计算: 50001-1000000
(2) 父进程负责存储。
//demo2.c#include <stdio.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>int idx = 0;int fddata;/// 信号处理函数void deal(int s){int status;if(s == SIGCHLD){wait(&status);idx++;if(idx == 2){close(fddata);printf("任务完成\n");exit(-1);}}}int isprimer(int s){int i = 2;for(i; i<s; ++i){if(s%i== 0)return 0;}return 1;}main(){int a,b;int id = 1;int fd[2];signal(SIGCHLD,deal);pipe(fd);/// 创建有名管道while(1){if(id == 1){a=2;b=50000;}if(id == 2){a=50001;b=100000;}if(fork()){id++;if(id > 2)break;continue;}else{ /// 子进程int i;close(fd[0]);for(i=a; i<=b;++i){if(isprimer(i)){write(fd[1],&i,sizeof(int));}}printf("[%d]任务完成!\n",getpid());exit(0);}}int re;char buf[20];// 打开文件准备存储close(fd[1]);fddata = open("/tmp/result.txt",O_RDWR | O_CREAT,0666);while(1)// 父进程{read(fd[0],&re,sizeof(int));sprintf(buf,"%d\n",re);write(fddata,buf,strlen(buf)); ///以流的方式写入文件}}
————————————————————————————————
$ cat resut.txt 查看
$ cat resut.txt | more 10 --- 每次只显示10个数据
________________________________
- 12----进程间的通信:管道
- 进程间的通信:管道
- 进程间的通信:管道
- Linux进程间的通信--管道通信
- 进程间管道通信
- 进程间通信: 管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信----管道
- 进程间通信----管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信--管道
- 进程间通信-管道
- 进程间管道通信
- 进程间管道通信
- FMS服务器和客户端之间的远程调用实现
- hdu4973 线段树
- Android 设计模式之适配器模式
- 【2014秋季版】【辛星php】【0】清晰的认识一下PHP语言
- Git
- 12----进程间的通信:管道
- 学习FPGA的网站推荐
- UISearchBar与数据库结合使用
- Android:SQLite 事务处理
- 构造函数不能是虚函数的原因
- 测试java中静态常量和静态变量的区别
- 常见算法在实际项目中的应用
- MRC下的 initWithFormat: 和 stringWithFormat:
- Malloc/new和delete/free的区别