进程间通信(IPC)(1)—— 管道、共享内存
2016-07-21 22:36
459 查看
一 有哪些进程间通信方式
IPC就是两个或者多个进程之间的数据交互。IPC的方法:
1. 文件
2. 信号(signal)
3. 管道
4. 共享内存
5. 消息队列(会做一个综合练习)
6. 信号量集(与前面学的信号无关semaphore)
7. 网络编程(socket)
….
二 管道
管道是Unix最古老的IPC方式,现在已很少使用。4 5 6 用法类似,统称为XSI IPC,遵守相同的规范。
管道分为有名管道和无名管道。有名管道由程序建立管道文件,用于进程间的通信。而无名管道由内核建立管道文件,用于fork()创建的父子进程之间的通信。
管道是通过管道文件(媒介) 进行交互的。管道文件和 普通文件有所区别。管道文件是 mkfifo命令创建的或者mkfifo()函数新建,管道文件的后缀 .pipe。
管道文件只是数据的中转站,不存储数据。因此,只有读写都ok时,才能畅通。(echo cat)
管道的使用和文件一样的,但管道文件的创建必须用mkfifo。
1 有名管道
pipea.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main(){ int fd = open("a.pipe",O_WRONLY); //O_CREAT用不到,因为它无法创建管道文件 //O_RDWR同时开通了读管道和写管道 if(fd==-1) perror("open"),exit(-1); int i; for(i=0;i<100;i++){ write(fd,&i,4); } close(fd); } pipeb.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main(){ int fd = open("a.pipe",O_RDONLY); if(fd==-1) perror("open"),exit(-1); int i; for(i=0;i<100;i++){ int x; read(fd,&x,4); printf("x=%d\n",x); } close(fd); }
2 无名管道
管道文件由内核管理,只能用于 fork()创建的父子进程之间。借助pipe() 创建一个读管道,一个写管道。
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main(){ int fd[2] = {}; pipe(fd);//创建了两个管道,fd[0] 读 fd[1] 写 pid_t pid = fork(); if(pid == 0){//子进程 close(fd[1]);//关闭写端 int i; for(i=0;i<100;i++){ int x; read(fd[0],&x,4); printf("%d ",x); fflush(0); } close(fd[0]); exit(0); } close(fd[0]); int i; for(i=100;i<200;i++){ write(fd[1],&i,4); usleep(100000); } close(fd[1]); }
三 XSI IPC结构
XSI IPC 包括共享内存、消息队列、信号量集,隶属于同一个规范,有着共同的特征。每个XSI IPC结构 都是在内核中存储和维护的,用ipcs命令可以查看,用ipcrm命令可以删除。
ipcs -a 查看全部IPC结构
-m 查看共享内存
-q 查看消息队列
-s 查看信号量集
ipcrm 用法和ipcs 类似,但后面要跟上ID。
每个XSI IPC结构都有两个东西定位:外部到内核要用key,内核中使用ID标识。
key的生成:
key的类型key_t,其实是一个长整形,有3种方法得到key:
1 使用宏 IPC_PRIVATE 做key,但这种方式无法实现 进程间的通信(私有),极少使用。
2 把所有的key定义在一个头文件中,用宏定义。
3 使用ftok()函数生成key,参数:真实存在的路径和项目编号(0-255)。
ID的生成:
IPC结构在内核中都用ID做唯一标识,创建/获取ID都有对应的函数,比如:
int shmid = shmget(key,…);
int msgid = msgget(key,…);
调用XXXget()时,都有一个flags,创建时的值为
权限|IPC_CREAT|IPC_EXCL
IPC_CREAT - 创建
IPC_EXCL - 如果存在会返回错误
和O_CREAT O_EXCL 类似。
IPC结构都有一个特殊的操作函数,提供查询、修改和删除的功能。
函数名:XXXctl(),比如:shmctl() msgctl()
参数cmd提供功能:
IPC_STAT - 查询IPC结构的属性/状态
IPC_SET - 修改IPC结构的相关属性,但只能修改权限
IPC_RMID - 删除IPC结构,按ID删除
3.1 共享内存
每个进程内存独立的,无法直接互访。共享内存就是内核管理一段内存(物理内存),这段物理内存允许 每个进程进行映射。编程步骤:
1 系统创建/获取共享内存(拿到物理内存)
ftok()-> key
shmget() -> 创建/获取共享内存,返回ID
2 挂接共享内存(映射) shmat()
3 使用共享内存
4 脱接共享内存(解除映射) shmdt()
5 如果共享内存不再被使用,可以删除。 shmctl()
共享内存的优缺点:
优点:速度最快的IPC,高效率
缺点:如果有多个进程写数据,将会产生覆盖问题,导致数据的错误和不完整。
#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> int main(){ key_t key = ftok(".",100);//生成key if(key==-1) perror("ftok"),exit(-1); int shmid = shmget(key,4, 0666|IPC_CREAT|IPC_EXCL);//创建shm if(shmid==-1) perror("shmget"),exit(-1); void* p = shmat(shmid,0,0);//挂接共享内存 int* pi = p; *pi = 1000; int res = shmdt(p);//脱接共享内存 if(res==-1) perror("shmdt"),exit(-1); printf("all ok\n"); }//练习:写shmb.c,利用共享内存取出1000并打印 #include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> int main(){ key_t key = ftok(".",100);//生成key if(key==-1) perror("ftok"),exit(-1); int shmid = shmget(key,0,0);//获取shm if(shmid==-1) perror("shmget"),exit(-1); void* p = shmat(shmid,0,0);//挂接共享内存 int* pi = p; printf("*pi=%d\n",*pi); int res = shmdt(p);//脱接共享内存 if(res==-1) perror("shmdt"),exit(-1); }
shmctl.c #include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> int main(){ key_t key = ftok(".",100); int shmid = shmget(key,0,0); if(shmid==-1) perror("shmget"),exit(-1); struct shmid_ds ds; shmctl(shmid,IPC_STAT,&ds);//取shm的状态 printf("key=%x\n",ds.shm_perm.__key); printf("mode=%o\n",ds.shm_perm.mode); printf("size=%d\n",ds.shm_segsz); printf("cpid=%d\n",ds.shm_cpid); printf("nattch=%d\n",ds.shm_nattch);//挂接数 ds.shm_perm.mode = 0640;//修改状态 可以改 ds.shm_segsz = 40;//不可以修改 shmctl(shmid,IPC_SET,&ds);//在修改状态 //shmctl(shmid,IPC_RMID,0); //删除 }
相关文章推荐
- 2016ACM暑假集训 - Sacrament of the sum
- Fragment的声明周期整理
- L2-003. 月饼-PAT团体程序设计天梯赛GPLT
- Java内存分配全面浅析
- codeforces 632C
- jvm参数解析
- Retrofit解析网页Json数据简单实例
- linux系统常用命令
- jvm参数解析
- 2016.7集训总结
- 嵌入式通讯协议设计
- 基本排序算法示例
- lamp
- Java反射机制
- Java反射机制
- StreamTokenizer类详解
- Linux学习_信号
- angularJS 指令二
- 信号(2)
- LeetCode - 151. Reverse Words in a String