Unix进程间通信: 命名管道,共享内存,内存映射,消息队列
2010-12-12 15:31
169 查看
在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
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开发】进程间通信命名管道-共享内存-内存映射-消息队列-信号量
- 管道、命名管道、信号、消息队列、共享内存、内存映射、信号量、套接字(Python)
- linux c++ 多进程 匿名管道 命名管道 消息队列 信号量 共享内存 内存映射
- (命名)管道,信号量,消息队列,共享内存,信号,socket
- 管道 消息队列 共享内存的优缺点
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- 进程间通信:管道,信号量,共享内存,消息队列
- 进程间通信之管道,消息队列,共享内存
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- 进程间通信的方式——信号、管道、消息队列、共享内存
- 消息队列和管道的区别以及和共享内存相比效率低的原因
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- 进程间通信的几种方式:管道、信号、消息队列、共享内存
- 现在最常用的进程间通信的方式有:管道,信号,信号量,消息队列,共享内存。
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux进程间通信方式--信号,管道,消息队列,信号量,共享内存
- 进程间通信——管道,消息队列,共享内存
- Linux进程间通信--信号,管道,消息队列,信号量,共享内存,socket
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- 进程间通信的方式-信号、管道、消息队列、共享内存