在Unix平台上,建立命名管道是创建了一个fifo文件,和在shell下面用mkfifo命令的效果是一样的。看起来这个管道文件就是一个普通的文件系统瓜挂载点,但是它只不过是作为一个名称存在,实际的内容是一块系统管理的共享内存。这个fifo文件读写端同时处于open状态,才能进行通信。否则,一端open的话,会处于阻塞状态。下面两个例子程序,实现的内容是一样的。父子进程间通过命名管道来通信。当然,如果为了保证读写的顺序,那么就用wait()函数。
1. 最简单的情况:程序输出hello!
> cat r.C
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
int main(void){
char FIFO[]=".myfifo";
char msg[8]="hello!\n";
char buf[8]={0};
unlink(FIFO);
mkfifo(FIFO,0666);
if(fork()>0){
int fd=open(FIFO,O_WRONLY);
write(fd,msg,sizeof(msg));
close(fd);
}else{//child
int fd=open(FIFO,O_RDONLY);
read(fd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,sizeof(buf));
close(fd);
}
return 0;
}
2. 稍微复杂点的情况,用wait()函数保证调用顺序:
注意,wait之前,必须保证两方的open都已经调用成功了。
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
int main(void){
char FIFO[]=".myfifo";
char msg[8]="hello!\n";
char buf[8]={0};
unlink(FIFO);
mkfifo(FIFO,0666);
pid_t pid=fork();
int status;
if(pid>0){//father
int fd=open(FIFO,O_RDONLY);
wait(&status);
read(fd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,sizeof(buf));
close(fd);
}else{//child
int fd=open(FIFO,O_WRONLY);
write(fd,msg,sizeof(msg));
close(fd);
}
return 0;
}
3. 更复杂的情况: 在两个独立的进程之间共享这个命名管道。注意s.C作为子进程r.C作为主进程。
>cat s.C(这个要被编译成./s)
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
int main(void){
char FIFO[]=".myfifo";
char msg[8]="hello!\n";
int fd=open(FIFO,O_WRONLY);
write(fd,msg,sizeof(msg));
close(fd);
return 0;
}
> cat r.C
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
int main(void){
char FIFO[]=".myfifo";
char buf[8]={0};
unlink(FIFO);
mkfifo(FIFO,0666);
pid_t pid=fork();
int status;
if(pid>0){//father
int fd=open(FIFO,O_RDONLY);
wait(&status);
read(fd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,sizeof(buf));
close(fd);
}else{//child
execl("./s",NULL);
}
return 0;
}
输出结果仍然是hello!
4. 如果不用命名管道,用共享内存或者内存映射的方式,效果是一样的,因为管道本身就是一种共享内存。共享内存是系统管理的不需要经过文件,内存映射则必须创建一个中间文件。相比较而言,Windows平台上面共享内存和内存映射是一个函数CreateFileMapping的不同参数而已。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<sys/mman.h>
struct p{
int age;
int height;
};
int main(void){
key_t key=1234;
int status;
int shmfd=shmget(key,sizeof(p),0666|IPC_CREAT);
if(shmfd==-1)exit(1);
p* pt=(p*)shmat(shmfd,(void*)0,0);
if(pt==(void*)-1)exit(2);
int fd=open("my.txt",O_CREAT|O_RDWR|O_TRUNC,00777);
p* pm=(p*)mmap(NULL,sizeof(p),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
pid_t pid=fork();
if(pid>0){//father
wait(&status);
printf("%d,%d\n",pt->age,pt->height);
shmdt((char*)pt);
shmctl(key,IPC_RMID,0);
printf("%d,%d\n",pm->age,pm->height);
msync((char*)pm,sizeof(p),MS_SYNC);
munmap((char*)pm,sizeof(p));
close(fd);
}else{//child
pt->age=20;
pt->height=180;
shmdt((char*)pt);
pm->age=30;
pm->height=170;
}
return 0;
}
程序运行的结果是,父进程读取了子进程对共享内存的写入内容,输出:
20 180
30 170
5. 消息队列的用法也基本一样。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/wait.h>
#include<sys/ipc.h>
#include<sys/msg.h>
struct p{
int age;
int height;
};
int main(void){
int msgfd=msgget(IPC_PRIVATE,0700);
if(msgfd<0)exit(1);
p pbuf={20,180};
int status;
pid_t pid=fork();
if(pid>0){//father
wait(&status);
p rev;
msgrcv(msgfd,&rev,sizeof(p),0,IPC_NOWAIT);
printf("%d %d\n",rev.age,rev.height);
msgctl(msgfd,IPC_RMID,NULL);
}else{//child
msgsnd(msgfd,&pbuf,sizeof(p),IPC_NOWAIT);
}
return 0;
}
程序输出
20 180
分享到:
相关推荐
Linux和OS X上各种进程间通信(IPC)方法的示例实现和基准。 光谱 实施以下IPC方法。 要衡量自己的连续吞吐量,我们提出和两个进程之间的后部(即,乒乓)发送一条消息。 方法 100字节消息 1千字节消息 Unix信号 ...
由于我只能上传不大于20M的内容,...第6章 传统的unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6. 5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量
第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6.5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章基于socket的进程间通信 7.1系统调用...
第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6. 5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章 基于socket的进程间通信 ...
第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6.5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章基于socket的进程间通信 7.1系统调用...
第17章 高级进程间通信 17.1 引言 17.2 基于STREAMS的管道 17.2.1 命名的STREAMS管道 17.2.2 唯一连接 17.3 UNIX域套接字 17.3.1 命名UNIX域套接字 17.3.2 唯一连接 17.4 传送文件描述符 ...
387 14.8 readn和writen函数 389 14.9 存储映射I/O 390 14.10 小结 395 习题 396 第15章 进程间通信 397 15.1 引言 397 15.2 管道 398 15.3 popen和pclose函数 403 15.4 协同进程 408 15.5 FIFO ...
第17章 高级进程间通信 469 17.1 引言 469 17.2 基于STREAMS的管道 469 17.2.1 命名的STREAMS管道 472 17.2.2 唯一连接 473 17.3 UNIX域套接字 476 17.3.1 命名UNIX域套接字 477 17.3.2 唯一连接 ...
关系、信号、线程、线程控制、守护进程、各种I/O、进程间通信、网络IPC、伪终端等方面的内容,还在 此基础上介绍了多个应用实例,包括如何创建数据库函数库以及如何与网络打印机通信等。此外,还在附 录中给...
第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6. 5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 《LINUX内核源代码情景分析(下册)》图书...
第17章 高级进程间通信 469 17.1 引言 469 17.2 基于STREAMS的管道 469 17.2.1 命名的STREAMS管道 472 17.2.2 唯一连接 473 17.3 UNIX域套接字 476 17.3.1 命名UNIX域套接字 477 17.3.2 唯一连接 ...
第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6. 5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 《LINUX内核源代码情景分析(下册)》图书...
关系、信号、线程、线程控制、守护进程、各种I/O、进程间通信、网络IPC、伪终端等方面的内容,还在 此基础上介绍了多个应用实例,包括如何创建数据库函数库以及如何与网络打印机通信等。此外,还在附 录中给...
4.3.1 System V的进程间通信机制 44 4.3.2 消息队列 44 4.3.3 信号量 45 4.3.4 共享存储区 47 第5章 PCI 49 5.1 PCI的地址空间 49 5.2 PCI配置头 50 5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥...
4.3.1 System V的进程间通信机制 44 4.3.2 消息队列 44 4.3.3 信号量 45 4.3.4 共享存储区 47 第5章 PCI 49 5.1 PCI的地址空间 49 5.2 PCI配置头 50 5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥...
4.3.1 System V的进程间通信机制 44 4.3.2 消息队列 44 4.3.3 信号量 45 4.3.4 共享存储区 47 第5章 PCI 49 5.1 PCI的地址空间 49 5.2 PCI配置头 50 5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥...
4.3.1 System V的进程间通信机制 44 4.3.2 消息队列 44 4.3.3 信号量 45 4.3.4 共享存储区 47 第5章 PCI 49 5.1 PCI的地址空间 49 5.2 PCI配置头 50 5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 ...
4.3.1 System V的进程间通信机制 44 4.3.2 消息队列 44 4.3.3 信号量 45 4.3.4 共享存储区 47 第5章 PCI 49 5.1 PCI的地址空间 49 5.2 PCI配置头 50 5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥...