文章目录
前言
基于上一篇博文,共享内存也是进程间通信的另一种方法,共享内存往往是和其他通信机制配合使用来实现进程间的相互通信。
以下是本篇文章正文内容,下面案例可供参考
一、什么是共享内存?
共享内存就是在内存中划出一块区域作为公共区域,允许多个进程共享这个存储区,在操作系统中,这段物理内存属于临界区资源,正是因为临界区资源可以共享数据不需要在客户端和服务器的多进程之间复制(即数据传递不再与内核相关),所以这是最快的一种进程间通信的方式。
二、共享内存用到的函数
使用共享内存的我们必须要知道的是:在多个进程之间同步访问一个给定的共享区域,这就涉及到进程的同步性,加入服务器进程使用共享存储区,那么客户端进程就不能同时访问共享存储区。一般情况下:信号量/记录锁/互斥量用于同步共享内存访问。我们用一张图来理解共享内存:
共享存储段中有内核维护的一个结构,该结构至少要为共享存储段包含以下结构体成员:
atruct shmid_ds{
struct ipc_perm shm_perm; /*see Section 15.6.2*/
size_t shm_segsz; /*size of segment in bytes */
pid_t shm_lpid; /*pid of last shmop*/
pid_t shm_cpid; /*pid of creater */
shmatt_t shm_nattch; /*number of current attaches */
time_t shm_atime; /*last-attach time */
time_t shm_dtime; /*last-detach time */
time_t shm_ctime; /*last-change time */
...
1、ftok () 函数
在上一篇博文中有详细讲解。
2、shmget () 函数
函数功能:
创建共享内存,成功则返回一个非负整数,失败返回-1;
函数原型:
#include<sys/shm.h>
int shmget(key_t key,size_t size,int flag);
参数说明:
size是需要共享存储段的内存容量,以字节为单位,在服务器进程中创建一个新段时必须指定其size;如果正在引用一个现存的客户端进程,那么size必须指定为0;
flag是权限标志,
3、shmat () 函数
函数功能:
启动进程对共享内存的访问,并把共享内存和当前访问的进程的内存空间连接,其返回值是共享存储段所连接的实际地址,成功则返回指向共享内存的第一个字节的指针,内核将使与该共享存储段相关的shmid_ds结构中的shm_nattch计数器的值+1;失败则返回-1;
函数原型:
#include<sys/shm.h>
void *shmat(int shmid,const void*addr,int flag);
参数说明:
shmid:是由shmget函数返回的共享内存标识;
*addr:是指定共享存储段连接到当前进程中的地址位置,一般为NULL,标识由系统决定共享内存的地址;
若 addr=0,则共享存储段连接到内核选择的第一个可用地址上;
若 addr≠0,并且没有指定的=SHM_RND(取整),则共享存储段连接到连接到addr所指定的地址上;
若 addr≠0,并且指定SHM_RND,则共享存储段连接到(addr-(addr mod SHMLBA(地边界地址倍数)))所表示的地址上。
4、shmdt () 函数
函数功能:
该函数时将共享存储段与正在连接的进程断开,成功则返回0,shmdt将使相关的shmid_ds结构中的shm_nattch计数器-1;失败则返回-1;
函数原型:
#include<sys/shm.h>
int shmdt(const void *addr)
参数说明:
*addr是函数返回的地址指针,调用成功返回0,失败则返回-1;
5、shmctl () 函数
函数功能:
用于控制共享存储段,执行多种操作。
函数原型:
#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
参数说明:
shmid是shmget函数返回的共享内存标识符;
cmd从下面三种命令中取得一种并在shmid指定的共享内存段上执行:
IPC_STAT:在共享存储段中取得shmid_ds结构,并存储在由buf指向的结构中;
IPC_SET:按照*buf结构中的值设置与它对应的共享存储段中shmid_ds结构中的部分字段;
IPC_RMID:从系统内核中删除这段共享存储段。
buf是一个结构指针,它指向共享内存模式和访问权限的结构,其结构体类型定义如下:
struct shmid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
}
三、共享内存在进程间通信使用的示例
1、创建一个student结构体共享内存并更新里面的成员内容:
/*********************************************************************************
* Copyright: (C) 2021 Mierya<2477326997@qq.com>
* All rights reserved.
*
* Filename: shared_mem_write.c
* Description: This file is Create a student structure to share memory and update the contents of its members
*
* Version: 1.0.0(04/02/2021)
* Author: Mierya <2477326997@qq.com>
* ChangeLog: 1, Release initial version on "04/02/2021 01:05:21 AM"
*
********************************************************************************/
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#define FTOK_PATH "/dev/zero" /* 系统中必须存在文件夹的路径*/
#define FTOK_PROJID 0x22 /* 用户指定的子序号,取值范围1~255*/
typedef struct st_student
{
char name[64];
int age;
}t_student;
int main(int argc,char **argv)
{
key_t key;
int shmid;
int i;
t_student *student;
if((key=ftok(FTOK_PATH,FTOK_PROJID)) < 0) /*如果指定的文件夹和PROJ_ID计算并返回一个key_t类型的ID值小于0*/
{
printf("ftok() get IPC token failure: %s\n",strerror(errno));
return -1;
}
shmid = shmget(key,sizeof(t_student),IPC_CREAT|0666); /*
创建一段内存容量以字节为单位的共享内存,并返回给shmid,其权限为0666*/
if(
shmid < 0)
{
printf("shmget() create shared memory failure: %s\n",strerror(errno)); /*
当创建共享内存失败,输出失败及原因*/
return -2;
}
student = shmat(shmid,NULL,0); /* 创建共享内存成功,shmat函数启动对该共享内存的访问,并进入到进程中去*/
if((void *)-1 == student )
{
printf("shmat() alloc shared memory failure: %s\n",strerror(errno));
return -2;
}
strncpy(student->name,"lihua",sizeof(student->name));
student->age = 18;
for(i=0;i<4;i++)
{
student->age ++;
printf("Student '%s' age [%d]\n",student->name,student->age);
sleep(1);
}
shmdt(student); /* 将共享内存从进程中分离,但不删除共享内存*/
shmctl(shmid,IPC_RMID,NULL); /* 控制和处理共享内存,*/
return 0;
}
2、在另一个毫无关系的进程中同步访问该结构体里面的内容:
/*********************************************************************************
* Copyright: (C) 2021 Mierya<2477326997@qq.com>
* All rights reserved.
*
* Filename: shared_mem_read.c
* Description: This file is synchronize access to the contents of the student structure in another process
*
* Version: 1.0.0(04/02/2021)
* Author: Mierya <2477326997@qq.com>
* ChangeLog: 1, Release initial version on "04/02/2021 01:22:04 AM"
*
********************************************************************************/
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#define FTOK_PATH "dev/zero" /*系统中必须存在文件或文件夹的路径*/
#define FTOK_PROJID 0x22 /*用户指定的子序号,取值范围为1~255*/
typedef struct st_student
{
char name[64];
int age;
}t_student;
int main(int argc,char **argv)
{
key_t key;
int shmid;
int i;
t_student *student;
if((key=ftok(FTOK_PATH,FTOK_PROJID)) < 0) /*如果指定的文件夹和PROJ_ID计算并返回一个key_t类型的ID值小于0*/
{
printf("ftok() get IPC token failure: %s\n",strerror(errno));
return -1;
}
shmid = shmget(key,sizeof(t_student),IPC_CREAT|0666); /*创建一段内存容量以字节为单位的共享内存,并返回给shmid*/
if(shmid < 0)
{
printf("shmget() create shared memory failure: %s\n",strerror(errno)); /*创建共享内存失败时,输出失败及原因*/
return -2;
}
student = shmat(shmid,NULL,0); /*创建内存成功,shmat函数启动对该共享内存的访问,并进入到student进程中去*/
if( (void *)-1 == student )
{
printf("shmat() alloc shared memory failure: %s\n",strerror(errno));
return -2;
}
for(i=0;i<4;i++)
{
printf("Student %s age %d\n",student->name,student->age);
sleep(1);
}
shmctl(shmid,IPC_RMID,NULL); /*控制和处理共享内存*/
return 0;
}
运行结果如下:
创建一个student结构体共享内存并更新里面的内容:
在另一个进程中同步访问该结构体中的内容:
四、总结
以上就是今天要讲的内容,本文仅仅简单介绍了进程间通信的另一种方法—共享内存,共享内存在计算机系统中可以被CPU大容量访问,这种方法不仅适用于一个程序的多进程间通信,也适用于多个程序间信息的传递。
恭请指正!