Chinaunix首页 | 论坛 | 博客
  • 博客访问: 140159
  • 博文数量: 10
  • 博客积分: 2431
  • 博客等级: 大尉
  • 技术积分: 266
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-02 00:56
文章分类
文章存档

2016年(1)

2013年(2)

2011年(3)

2010年(4)

分类: C/C++

2010-09-02 10:46:51

        在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

Unix和Window平台IPC: 匿名管道
Unix进程间通信: 命名管道,共享内存,内存映射,消息队列
Unix进程间通信: 两种不同的信号量
Unix编程 线程局部存储和线程同步
Windows平台进程间通信: 用Windows消息做IPC
Windows平台进程间通信: 命名管道
Windows平台进程间通信: 互斥体,同步段,信号量
Windows平台进程间通信: 发送线程消息(PostThreadMessage)
Windows编程杂项 共享数据段,线程局部存储,事件对象
阅读(3552) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~