您的位置:首页 > 其它

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐