行业知识
《Linux C编程实战》笔记:共享内存
共享内���是分配一块能被其他进程访问的内存。每个共享内存段在内核中维护一个内部数据结构shmid_ds(和消息队列、信号量一样),该结构定义在头文件linux/shm.h中,这是我从源码里抄的
#includestruct shmid_ds {struct ipc_permshm_perm;/* 操作许可 */intshm_segsz;/* size of segment (bytes) */__kernel_old_time_tshm_atime;/* 最后一个进程访问共享内存的时间 */__kernel_old_time_tshm_dtime;/* 最后一个进程离开共享内存的时间 */__kernel_old_time_tshm_ctime;/* last change time */__kernel_ipc_pid_tshm_cpid;/* pid of creator */__kernel_ipc_pid_tshm_lpid;/* pid of last operator */unsigned shortshm_nattch;/* 当前使用该共享内存段的进程数量 */unsigned short shm_unused;/* compatibility */void *shm_unused2;/* ditto - used by DIPC */void*shm_unused3;/* unused */}; 但是总结了上一节的经验,我发现sys/shm.h也同样定义了该结构体,所以真正编写代码时可能只用包含sys/shm.h头文件
共享内存的创建与操作
共享内存区的创建
Linux下使用函数shmget来创建一个共享内存区,或者访问一个已经存在的共享内存区。该函数定义在头文件linux/shm.h中?
但是根据我自己的linux来看,linux/shm.h并没有该函数,在sys/shm.h中定义了该函数,所以以事实为准,认为该函数定义在sys/shm.h中。
并且根据实践,linux/shm.h和sys/shm.h同时包含的话编译不给过,所以下面就只用sys/shm.h了
#include int shmget(key_t key, size_t size, int shmflg);
- key:用于标识共享内存段的关键字。
- size:要创建的共享内存段的大小(以字节为单位)。
- shmflg:用于指定创建共享内存段的访问权限和其他标志位。
返回值:
- 如果成功,返回一个非负整数,该整数是共享内存段的标识符(即共享内存的ID)。
- 如果失败,返回 -1,并设置 errno 来指示错误的原因。
该函数用法与消息队列和信号量集的创建一样。key一般通过ftok得到,shmflg的话一般是IPC_CREATE或者IPC_EXCL|IPC_CREATE 再加上权限的组合。具体含义请到消息队列的那一节查看:《Linux C编程实战》笔记:消息队列-CSDN博客
如果是创建的话,size要大于0;如果只是访问,size置为0.
共享内存区的操作
在使用共享内存区之前,必须通过shmat函数将其附加到进程的地址空间。进程与共享进程就建立了连接。shmat调用成功后就会返回一个指向共享内存区的指针,使用该指针就可以访问共享内存区了,如果失败返回-1.该函数定义在sys/shm.h中(这也是我根据实际改的,书上还是说是linux/shm.h)
#include void *shmat(int shmid, const void *shmaddr, int shmflg);
- shmid:要连接的共享内存段的标识符(由 shmget 函数返回的ID)。
- shmaddr:指定共享内存连接到进程地址空间的起始地址,通常设置为 NULL,让系统自动选择一个合适的地址。
- shmflg:用于指定连接共享内存的选项,通常为0。
返回值:
- 如果成功,返回一个指向共享内存段第一个字节的指针。
- 如果失败,返回 (void *) -1,并设置 errno 来指示错误的原因。
当进程结束时使用共享内存区时,要通过函数shmdt断开与共享区内存的连接。该函数声明在sys/shm.h
#include int shmdt(const void *shmaddr);
参数shmaddr为shmget的返回值。该函数调用成功后,返回0,否则返回-1.进程脱离共享内存区后,数据结构shmid_ds中的shm_nattch就会减1.但是共享内存段依然存在,只有shm_nattch为0后,即没有任何进程再使用该共享内存区,共享内存区才应该在内核中被删除。一般来说,一个进程终止时,他所附加的共享内存区都会自动脱离。
共享内存区的控制
#include int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- shmid 是共享内存区的标识符,通常由 shmget 函数返回。
- cmd 是要执行的操作,可以是各种控制命令之一。
- buf 是一个指向 shmid_ds 结构的指针,用于传递或获取与共享内存相关的信息。
常用的控制命令包括:
- IPC_STAT:获取共享内存区的状态信息,并将其存储在 buf 中。
- IPC_SET:设置共享内存区的状态信息,buf 中包含了要设置的信息。
- IPC_RMID:删除共享内存区。
如果你想删除共享内存区,可以将 cmd 参数设置为 IPC_RMID,并将共享内存区的标识符 shmid 作为 shmctl 函数,buf设置为NULL。
示例程序
本例通过读写者问题(不考虑优先级)来演示共享内存和呃呃信号量如何配合使用。这里的读者写者问题要求一个进程读共享内存的时候,其他进程不能写内存;当一个进程写共享内存的时候,其他进程不能读内存
首先定义了一个包含公用函数的头文件sharemem.h
#pragma once//这是C++的,毕竟我用的都是g++编译器#include#include#include#include#include#include#include#include#define SHM_SIZE 1024union semun{ int val; struct semid_ds *buf; unsigned short *array;};int createsem(const char *pathname,int proj_id,int members,int init_val){//创建信号量集 key_t msgkey; int index,sid; union semun semopts; if((msgkey=ftok(pathname,proj_id))==-1){ perror("ftok error!\n"); return -1; } if((sid=semget(msgkey,members,IPC_CREAT|0666))==-1){//创建信号量集 perror("semget call failed.\n"); return -1; } semopts.val=init_val; for(index=0;index
上一篇:主机怎么做服务器?
下一篇:【笔记】-编程语言以及应用领域