IPC之IPC_PRIVATE与ftok比较
在Linux中,可以使用IPC对象来进行进程间通信。IPC对象存在于内核中,多进程可以操作同一个IPC对象。
每个IPC对象都有一个唯一的编号,该编号是由系统分配的。那么不同的进程如何知道这个编号,进而通过它进行通信呢?下面以共享内存为例,进行分析。
方法一:通过ftok函数,产生相同的键值。
假设,进程p1创建了共享内存。可以在创建时,调用ftok函数,得到一个key值,调用shmget函数,该函数会返回所创建共享内存的编号,并将key和编号关联起来。若进程p2想利用这个共享内存和p1进程通信,也可以调用ftok函数,得到同样的key,再根据key值,调用shmget函数,就可以获得该共享内存的编号。该过程可以通过下面的图来表达。
ftok函数原型如下:
#include < sys/types.h>
#include < sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
第一个参数pathname,是一个存在的文件或目录名;
第二个参数proj_id,是非0整数(一般用i节点号)
该函数会返回一个key值,先运行的进程根据key来创建对象,后运行的进程根据key来打开对象。示意图如下:
使用 ftok创建共享内存,毫无关系的进程,可以通过得到同样的key,来操作同一个共享内存,对共享内存进行读写时,需要利用信号量进行同步或互斥。
方法二:使用IPC_PRIVATE对象
使用IPC_PRIVATE创建的IPC对象, key值属性为0,和IPC对象的编号就没有了对应关系。这样毫无关系的进程,就不能通过key值来得到IPC对象的编号(因为这种方式创建的IPC对象的key值都是0)。因此,这种方式产生的IPC对象,和无名管道类似,不能用于毫无关系的进程间通信。但也不是一点用处都没有,仍然可以用于有亲缘关系的进程间通信。示例程序如下:
#include < stdio.h>
#include < stdlib.h>
#include < errno.h>
#include < sys/ipc.h>
#include < sys/types.h>
#include < sys/shm.h>
#include < string.h>
#define MAXSIZE 1024
int main()
{
int shmid;
char *p = NULL;
pid_t pid;
#if 0
key_t key;
if ((key = ftok(".", 'a')) == -1)
{
perror("ftok");
exit(-1);
}
#endif
if ((shmid = shmget(IPC_PRIVATE, MAXSIZE, 0666)) == -1)
{
perror("shmget");
exit(-1);
}
if ((pid = fork()) == -1)
{
perror("fork");
exit(-1);
}
if (pid == 0)
{
if ((p = shmat(shmid, NULL, 0)) == (void *)-1)
{
perror("shmat");
exit(-1);
}
strcpy(p, "hello\n");
system("ipcs -m");
if (shmdt(p) == -1)
{
perror("shmdt");
exit(-1);
}
system("ipcs -m");
}
else
{
getchar();
if ((p = shmat(shmid, NULL, 0)) == (void *)-1)
{
perror("shmat");
exit(-1);
}
printf("%s\n", (char *)p);
if (shmctl(shmid, IPC_RMID, NULL) == -1)
{
perror("RM");
exit(-1);
}
}
return 0;
}
该程序中,父进程使用IPC_PRIVATE方式创建了共享内存,然后fork产生了子进程,由于子进程是复制父进程的方式产生的,因此,子进程也可以操作共享内存。子进程往共享内存里写了内容后,父进程可以读到。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3.使用IPC_PRIVATE方式注意
(1)int shmID=shmget(IPC_PRIVATE,len,IPC_CREAT|0600);需要在父子进程都可见的地方调用(即在创建子进程之前),否则不能实现内存的共享
因为通过IPC_PRIVATE这个key获得的id不一样,其他通过ftok获得的key来shmget获得的id在程序每次运行中是一样的。ftok参数一样的话每次程序运行中返回值都一样。
4.ipcs -m status 栏
nattch 是连接数目,dest 表示共享内存段已经被删除,但是仍然有程序在连接着它。
“status栏中列出当前共享内存的状态,当该段内存的mode字段设置了SHM_DEST位时就会显示"dest"字样,
当用户调用shmctl的IPC_RMID时,内核首先看有多少个进程还和这段内存关联着,如果关联数为0,就会销毁(释放)这段内存,否则就设置这段内存的mode位SHM_DEST,”
5.调用shmctl(shmID,IPC_RMID,NULL)或者shell 命令 ipcrm -m 不是会立刻删除共享内存,是向上面那样先置dest,并且此时共享内存中的数据仍然可以使用(即不影响正在使用共享内存的部分,但是若置为dest后再通过shmget通过同样的key来获取shmID时,shmID和删除前就不一样了),然后等待关联数为0才删除。shmdt是用来释放共享内存链接的,进程退出会调用shmdt。
并且共享内存被置dest后可以成功调用shmctl(shmID,IPC_RMID,NULL)或者shell 命令 ipcrm -m ,但是当关联数为0,共享内存被删除后,再调用 这些命令就会出错。
shmctl(shmID,IPC_RMID,NULL)可以被每个使用共享内存的进程内调用多次,但至少由一个进程来调用一次,否则不能删除共享的内存,但是shmdt只能对应相应的shmget调用一次。
3.4.5部分的代码如下:
- //shmem.cpp
- //g++ shmem.cpp -lpthread -o shmem
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include<unistd.h>
- #include<iostream>
- #include<cstdlib>
- #include<pthread.h>
- #include <string.h>
- #include <signal.h>
- #include <errno.h>
- #include <stdio.h>
- structargv_t{
- intshmID;
- };
- void*thread(void* argv){
- argv_t tmp=*(argv_t*)argv;
- char* addr=(char*)shmat(tmp.shmID,0,0);
- for(inti=0;i<5;i++){
- //sleep(2);
- std::cout<<"thread sending"<<std::endl;
- strcpy(addr,"Hello");
- }
- std::cout<<"thread :threadID="<<pthread_self()<<",pid="<<getpid()<<",parent pid ="<<getppid()<<std::endl;
- /*if(-1==shmctl(tmp.shmID,IPC_RMID,NULL)){
- std::cout<<"remove shared memory error:"<<errno<<std::endl;//error<<std::endl;
- perror(strerror(errno));
- }else{
- std::cout<<"remove shared memory ok"<<std::endl;
- }*/
- }
- intmain(intargc,char** argv){
- pthread_t thid;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
- argv_t arg;
- pid_t pid;
- intlen=5;
- intshmID=shmget(IPC_PRIVATE,len,IPC_CREAT|0600);
- if((pid=fork())==0){
- sleep(5);
- char* addr=(char*)shmat(shmID,0,SHM_RDONLY);
- for(inti=0;i<5;i++){
- std::cout<<"sub process pid="<<getpid()<<",parent pid"<<getppid()<<std::endl;
- std::cout<<"begin read sharedMem"<<std::endl;
- std::cout<<"s1"<<std::endl;
- std::cout<<"s2"<<std::endl;
- //if(i<=2)
- system("ipcs -m");
- std::cout<<"-----"<<i<<std::endl;
- if(i==2){
- char*cmd=newchar[50];
- sprintf(cmd,"ipcrm -m %d\0",shmID);
- system(cmd);
- }
- std::cout<<addr<<std::endl;
- //shmdt(addr);
- sleep(3);
- }//for
- std::cout<<"reveive end"<<std::endl;
- if(-1==shmctl(shmID,IPC_RMID,NULL)){
- std::cout<<"remove shared memory error:"<<errno<<std::endl;//error<<std::endl;
- perror(strerror(errno));
- }else{
- std::cout<<"remove shared memory ok"<<std::endl;
- }
- }elseif(pid>0){
- //shmID=shmget(IPC_PRIVATE,len,IPC_CREAT|0600);
- std::cout<<"shmID="<<shmID<<std::endl;
- arg.shmID=shmID;
- std::cout<<"I am the parent ,pid="<<getpid()<<",parent pid"<<getppid()<<std::endl;
- if((pthread_create(&thid,&attr,thread,(void*)&arg))!=0)
- std::cout<<"create thread failed"<<std::endl;
- else
- std::cout<<"create thread successed"<<std::endl;
- sleep(10);
- pthread_exit(0);//in main for wait
- }else{
- std::cout<<"fork sub process failed"<<std::endl;
- }
- returnEXIT_SUCCESS;
- }
部分输出结果:
6.信号量中IPC_PRIVATE类似于共享内存中,同样semget(IPC_PRIVATE,1,0666 | IPC_CREAT)需要在父子进程都可见的地方调用(即在创建子进程之前),否则不能实现内存的共享。
信号量中的semctl(semID[index],0,IPC_RMID,sem_union)删除是立即删除,不同于共享内存
IPC之IPC_PRIVATE与ftok比较相关推荐
- Linux进程通信中IPC对象——IPC_PRIVATE与ftok
在linux中,可以使用IPC对象来进行进程间通信.IPC对象存在于内核中,多进程可以操作同一个IPC对象.每个IPC对象都有一个唯一的编号,该编号是由系统分配的.那么不同的进程如何知道这个编号,进而 ...
- key_t IPC键和ftok函数详解和剖析
统建立IPC通讯(如消息队列.共享内存时)必须指定一个ID值.通常情况下,该id值通过ftok函数得到. ftok原型如下: key_t ftok( char * fname, int id ) fn ...
- 【IPC通信】key_t键和ftok函数
System V IPC分为三种: System V消息队列 System V信号量 System V共享内存区 这三种类型的IPC使用key_t值做为它们的名字.key_t这个数据类型在<sy ...
- System V IPC之信号灯
信号灯也叫信号量 用于进程/线程同步或互斥的机制 信号灯的类型 1.Posix 无名信号灯 2.Posix 有名信号灯 3.System V 信号灯 信号灯的含义 计数信号灯(1和2都是) Syste ...
- linux 共享内存_linux进程间通信----IPC篇(一)----共享内存初识篇
先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题 一 what 所 ...
- UNIX环境高级编程——创建与打开IPC通道
创建或打开一个IPC对象的三个getXXX函数的第一个参数key是类型为key_t的IPC键,返回值identifier是一个整数标识符.该标识符不同于ftok函数的id参数.对于key值,应用程序有 ...
- Linux C 进程间的IPC通信 之 共享内存(一)
1.IPC(inter - process communication)通信 共享内存.消息队列.信号灯 2.库 <sys/shm.h> 2-1 创建共享内存 int shmget( k ...
- linux进程间通信:system V 共享内存
文章目录 思维导图如下 通信原理 优势 运行流程 编程接口 编程实例 思维导图如下 通信原理 多个进程共享物理内存的同一块区域(通常称之为"段":segment) 抛弃了内核态消息 ...
- Linux 系统应用编程——进程间通信(下)
在前面,我们学习了传统的进程间通信方式--无名管道(pipe).有名管道(fifo)和信号(signal). 下面我们来学习 System V IPC 对象: 1.共享内存(share memory ...
最新文章
- 干货!这里有一份神经网络入门指导,请收下!
- 安装kvm的服务器开启vnc连接其虚拟机
- 如何访问云端的tcpserver_远程读写FTP文件,花生壳盒子+Serv-U快速实现远程访问...
- Android开发学习笔记-自定义组合控件
- Spyder 代码自动补全功能,代码提示
- 度微尔开发者联盟网站
- 如何在验证集加噪声_如何使用Python构建机器学习模型
- vue ---- 生命周期
- 机器学习基础(十九)—— Trick
- MicroPython ESP32 ADC(模拟量转数字量)示例
- 冰刃IceSword中文版 V1.22 绿色汉化修正版
- 飞塔防火墙MIB-OID列表
- Neo4j-Cypher
- TOP100summit 2017:小米唐沐等大咖精心挑选的100个年度研发案例实践
- A题 转换AV号(avtobv)
- 读取excel文件并使用matplotlib绘图(含柱状图、柱状图加数值的显示和直方图)
- 数据结构与算法常见笔试题
- RL02: Q-Learning, create an autonomous Taxi (Part 2/2)
- 橙色wamp的可能解决方法
- cocos2d-html5游戏图片资源选择