`

Unix进程间通信: 命名管道,共享内存,内存映射,消息队列

阅读更多

在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

分享到:
评论

相关推荐

    ipc-bench:进程间通信技术基准

    Linux和OS X上各种进程间通信(IPC)方法的示例实现和基准。 光谱 实施以下IPC方法。 要衡量自己的连续吞吐量,我们提出和两个进程之间的后部(即,乒乓)发送一条消息。 方法 100字节消息 1千字节消息 Unix信号 ...

    LINUX内核源代码情景分析(上).part1.rar

    由于我只能上传不大于20M的内容,...第6章 传统的unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6. 5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量

    Linux内核源代码情景分析 (上下册 高清非扫描 )

    第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6.5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章基于socket的进程间通信 7.1系统调用...

    linux 内核源代码分析

    第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6. 5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章 基于socket的进程间通信 ...

    linux内核源代码情景分析

    第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6.5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章基于socket的进程间通信 7.1系统调用...

    UNIX环境高级编程_第二版中文

    第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 传送文件描述符 ...

    unix环境编程电子书

    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 ...

    UNIX环境高级编程

    第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 唯一连接 ...

    UNIX环境高级编程_第2版.part2

     关系、信号、线程、线程控制、守护进程、各种I/O、进程间通信、网络IPC、伪终端等方面的内容,还在  此基础上介绍了多个应用实例,包括如何创建数据库函数库以及如何与网络打印机通信等。此外,还在附  录中给...

    Linux内核情景分析(非扫描版)

    第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6. 5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 《LINUX内核源代码情景分析(下册)》图书...

    UNIX环境高级编程(第二版中文)

    第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 唯一连接 ...

    Linux内核情景分析

    第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6. 5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 《LINUX内核源代码情景分析(下册)》图书...

    UNIX环境高级编程_第2版.part1

     关系、信号、线程、线程控制、守护进程、各种I/O、进程间通信、网络IPC、伪终端等方面的内容,还在  此基础上介绍了多个应用实例,包括如何创建数据库函数库以及如何与网络打印机通信等。此外,还在附  录中给...

    linux编程白皮书

    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 桥...

    Linux编程从入门到精通

    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 桥...

    Linux编程白皮书

    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 桥...

    LINUX编程白皮书

    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 ...

    LINUX编程白皮书 (全集)

    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 桥...

Global site tag (gtag.js) - Google Analytics