Linux 进程间的通信(二)—共享内存通信
共享内存通信简介
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个
进程共享
同一块内存区域,必然需要某种同步机制
,互斥锁
和信号量
都可以.
主要有以下几个API:shmget()、shmat()、shmdt()及shmctl()。
shmget()用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。
shmat()把共享内存区域映射到调用进程的地址空间中去,这样,进程就可以方便地对共享区域进行访问操作。
shmdt()调用用来解除进程对共享内存区域的映射。Shmctl()实现对共享内存区域的控制操作。
shmget函数
shmget函数的作用是在内存中获得一段共享内存区域。shmget函数原型如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key,int size,int shmflg)
函数返回值:该系统调用成功则返回共享内存段标识符ID,即shmid;若出错则返回-1。
函数传入参数key为IPC结构的键值,通常取常量IPC_PRIVATE;参数size为该共享内存区大小,如果创建一个新的区域,必须指定其size参数。如果引用一个已有的区域,则size应该为0;
参数shmflg:
0:取共享内存标识符,若不存在则函数会报错
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错
shmat函数
映射共享内存,使用函数shmat,它的作用是创建的共享内存映射到具体的进程空间去。shmat函数原型如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
char *shmat(int shmid,const void *shmaddr,int shmflg)
函数传入参数shmid为通过shmget得到的共享内存区标识符ID;参数shmaddr表示 将共享内存映射到指定位置,若为0则表示把该段共享内存映射到调用进程的地址空间,推荐采用这个参数;参数shmflg为选项位用来设置权限,常用的选项是SHM_RDONLY,表示以只读的方式共享内存,默认为0表示以读写的方式共享内存。
函数返回值:调用成功则返回被映射的段地址,否则返回−1。
shmdt函数
Shmdt函数用来撤销映射,其函数原型如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)
传入参数Shmaddr表示被映射的共享内存段地址。函数成功则返回0,否则返回−1。
案例
sharwrite.c
/* ************************************************************************
* Filename: sharewrite.c
* Description:
* Version: 1.0
* Created: 05/09/2020 02:45:05 AM
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (WCT),
* Company:
* ************************************************************************/
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
typedef struct{
char name[4];
int age;
} people;
int main(int argc, char** argv)
{
int shm_id,i;
key_t key;
char temp;
people *p_map;
char* name = "/home/wct/IPC";
key = ftok(name,0); // 将文件或目录路径转换为键值
if(key==-1){
perror("ftok error");
}
shm_id=shmget(key,4096,IPC_CREAT);
if(shm_id==-1)
{
perror("shmget error");
return -1;
}
p_map=(people*)shmat(shm_id,NULL,0);
temp='a' - 1;
for(i = 0;i<10;i++)
{
temp+=1;
memcpy((*(p_map+i)).name,&temp,1);
(*(p_map+i)).age=20+i;
}
if(shmdt(p_map)==-1){
perror(" detach error ");
}
return 0;
}
shareread.c
/* ************************************************************************
* Filename: shareread.c
* Description:
* Version: 1.0
* Created: 05/09/2020 03:08:12 AM
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (),
* Company:
* ************************************************************************/
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
typedef struct{
char name[4];
int age;
} people;
int main(){
int shm_id, i;
key_t key;
people * p_map;
key = ftok("/home/wct/IPC", 0); // 将文件或目录路径转换为键值
if( key == -1 ){
perror("ftok error");
}
shm_id = shmget(key, 4096, IPC_CREAT);
if( shm_id == -1 ){
perror("shmget error");
return -1;
}
p_map = ( people * ) shmat(shm_id, NULL, 0);
for( i = 0; i < 10; i ++ ){
printf("name: %s\tage: %d\n", ( * ( p_map + i)).name, ( *( p_map + i )).age);
}
if( shmdt( p_map) == -1 ){
perror("detach error");
}
return 0;
}
编译运行
编译后直接 ./
运行会发现程序出现段错误,这是权限原因,加上sudo 即可。
当然了这里不能同时运行这两个程序,因为这里没有加任何的同步机制。你可以自行加上同步机制,然后就可以同时运行了。去这里就可以顺便运行,加入了型号量