-
2021-01-28 14:29:16
shmget
int shmget(key_t key, size_t size, int flag);
key: 标识符的规则
size:共享存储段的字节数
flag:读写的权限
返回值:成功返回共享存储的id,失败返回-1
key_t key
-----------------------------------------------
key标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。
在IPC的通信模式下,不管是使用消息队列还是共享内存,甚至是信号量,每个IPC的对象(object)都有唯一的名字,称为“键”(key)。通过“键”,进程能够识别所用的对象。“键”与IPC对象的关系就如同文件名称之于文件,通过文件名,进程能够读写文件内的数据,甚至多个进程能够共用一个文件。而在IPC的通讯模式下,通过“键”的使用也使得一个IPC对象能为多个进程所共用。
Linux系统中的所有表示System V中IPC对象的数据结构都包括一个ipc_perm结构,其中包含有IPC对象的键值,该键用于查找System V中IPC对象的引用标识符。如果不使用“键”,进程将无法存取IPC对象,因为IPC对象并不存在于进程本身使用的内存中。
通常,都希望自己的程序能和其他的程序预先约定一个唯一的键值,但实际上并不是总可能的成行的,因为自己的程序无法为一块共享内存选择一个键值。因此,在此把key设为IPC_PRIVATE,这样,操作系统将忽略键,建立一个新的共享内存,指定一个键值,然后返回这块共享内存IPC标识符ID。而将这个新的共享内存的标识符ID告诉其他进程可以在建立共享内存后通过派生子进程,或写入文件或管道来实现。int size(单位字节Byte)
-----------------------------------------------
size是要建立共享内存的长度。所有的内存分配操作都是以页为单位的。所以如果一段进程只申请一块只有一个字节的内存,内存也会分配整整一页(在i386机器中一页的缺省大小PACE_SIZE=4096字节)这样,新创建的共享内存的大小实际上是从size这个参数调整而来的页面大小。即如果size为1至4096,则实际申请到的共享内存大小为4K(一页);4097到8192,则实际申请到的共享内存大小为8K(两页),依此类推。
int shmflg
-----------------------------------------------
shmflg主要和一些标志有关。其中有效的包括IPC_CREAT和IPC_EXCL,它们的功能与open()的O_CREAT和O_EXCL相当。
IPC_CREAT 如果共享内存不存在,则创建一个共享内存,否则打开操作。
IPC_EXCL 只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。
如果单独使用IPC_CREAT,shmget()函数要么返回一个已经存在的共享内存的操作符,要么返回一个新建的共享内存的标识符。如果将IPC_CREAT和IPC_EXCL标志一起使用,shmget()将返回一个新建的共享内存的标识符;如果该共享内存已存在,或者返回-1。IPC_EXEL标志本身并没有太大的意义,但是和IPC_CREAT标志一起使用可以用来保证所得的对象是新建的,而不是打开已有的对象。对于用户的读取和写入许可指定SHM_R和SHM_W,(SHM_R>3)和(SHM_W>3)是一组读取和写入许可,而(SHM_R>6)和(SHM_W>6)是全局读取和写入许可。
返回值
-----------------------------------------------
成功返回共享内存的标识符;不成功返回-1,errno储存错误原因。
EINVAL 参数size小于SHMMIN或大于SHMMAX。
EEXIST 预建立key所致的共享内存,但已经存在。
EIDRM 参数key所致的共享内存已经删除。
ENOSPC 超过了系统允许建立的共享内存的最大值(SHMALL )。
ENOENT 参数key所指的共享内存不存在,参数shmflg也未设IPC_CREAT位。
EACCES 没有权限。
ENOMEM 核心内存不足。
struct shmid_ds
-----------------------------------------------
shmid_ds数据结构表示每个新建的共享内存。当shmget()创建了一块新的共享内存后,返回一个可以用于引用该共享内存的shmid_ds数据结构的标识符。
include/linux/shm.h
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
struct ipc_perm
-----------------------------------------------
对于每个IPC对象,系统共用一个struct ipc_perm的数据结构来存放权限信息,以确定一个ipc操作是否可以访问该IPC对象。
struct ipc_perm {
__kernel_key_t key;
__kernel_uid_t uid;
__kernel_gid_t gid;
__kernel_uid_t cuid;
__kernel_gid_t cgid;
__kernel_mode_t mode;
unsigned short seq;
};//----------------------------------------
shmat
void *shmat(int shmid, const void * addr, int flag);
shmid:共享存储的id
addr:一般为0,表示连接到由内核选择的第一个可用地址上,否则,如果flag没有指定SHM_RND,则连接到addr所指定的地址上,如果flag为SHM_RND,则地址取整
flag:如前所述,一般为0
返回值:如果成功,返回共享存储段地址,出错返回-1
shmdt
int shmdt(void *addr);
addr:共享存储段的地址,以前调用shmat时的返回值
shmdt将使相关shmid_ds结构中的shm_nattch计数器值减1
shmctl
int shmctl(int shmid,int cmd,struct shmid_ds *buf)
shmid:共享存储段的id
cmd:一些命令,有:IPC_STAT,IPC_RMID,SHM_LOCK,SHM_UNLOCK
请注意,共享内存不会随着程序结束而自动消除,要么调用shmctl删除,要么自己用手敲命令去删除,否则永远留在系统中。
更多相关内容 -
apache启动报 shmget() failed: Invalid argument的解决方法
2021-01-10 06:54:28在用的apache服务器,启动报错: 代码如下:shmget() failed: Invalid argumentFailed to start up concurrent users module!经检查为kernel.shmmax设置未生效(copy另一系统的,数值设置大了) 如下: 代码如下:... -
SHMGET
2019-11-25 10:13:42名称 shmget---分配一个system V 共享内存段 摘要 #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg); 描述 shmg...http://man7.org/linux/man-pages/man2/shmget.2.html
名称
shmget---分配一个system V 共享内存段
摘要
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);描述
shmget --- 分配一个system V共享内存段
声明
#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);
描述
shmget() 返回了参数key的值关联的system V 共享内存段的标识符。它可能用于获取之前已经创建的共享内存段的标识符(当
shmflg是0, 且 key的值不是
IPC_PRIVATE), 也可能是创建一个新的段。一个新的共享内存段,它的的size 等于参数size对齐到PAGE_SIZE的整数倍;如果key的值是 IPC_PRIVATE,则会创建该新的的共享内存段; 如果key的值不是 IPC_PRIVATE, 但是该参数key没有对应的共享内存段且shmflg中设置了IPC_CREAT,则创建新的共享内存段。
如果shmflg 同时指定IPC_CREAT 和 IPC_EXCL ,并且该key的共享内存段已经存在,则 shmget() 会返回失败,errno 为 EEXIST。它仿照了open的 O_CREAT | O_EXCL 选项。
shmflg的值可以是如下所示的组合:
- IPC_CREAT 创建一个新的段。如果这个flag没有使用,shmget()会查找key对应的共享内存段,并且检查用户是否有访问该内存段的权限。
- IPC_EXCL 这个flag 与IPC_CREAT配合使用, 来确保这个调用会创建一个共享内存段。如果该内存段已经存在,则调用失败。
- SHM_HUGETLB (since Linux 2.6) 使用“huge pages” 分配一个共享内存段。详细信息见linux内核源文件Documentation/admin-guide/mm/hugetlbpage.rst
- SHM_HUGE_2MB, SHM_HUGE_1GB (since Linux 3.8) 与SHM_HUGETLB配合使用来选择 可选择的hugetlb page size(相应的是2MB 或 1GB),如果系统支持“multiple hugetlb page sizes”。 通常, “desired huge page size” 可以配置成“desired page size”的对数,使用 SHM_HUGE_SHIFT偏移6个bit 。因此,上面的两个常数定义如下:
#define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT)
#define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT)其它的信息可以查看mmap函数操作。
- SHM_NORESERVE (since Linux 2.6.15) 这个flag与mmap的MAP_NORESERVE flag相同的作用,不要为该内存段保留swap space。当保留swap space, 其中一个用户要保证它可能修改了内存段。当没有保留swap space, 在没有可用内存时, 一个用户可以获取SIGSEGV错误号。 可以在“proc”的/proc/sys/vm/overcommit_memory文件中查看。
除了上面的flags, shmflg的最小的9个bits 指定了owner、group和others的权限。这些bits有相同的格式, 相同的含义,它们与open操作的mode参数一致。当前,执行权限没有被使用。
当一个新的共享内存段被创建,它的内容被初始化为0值,并且它相关联的结构提数据,hmid_ds
(see shmctl(2)),按如下的方式进行初始化。- shm_perm.cuid 和 shm_perm.uid 被设置成调用进行的有效用户ID。
- shm_perm.cgid 和 shm_perm.gid 被设置成调用进程的有效 groupID。
- shm_perm.mode的最小的9个bits 被设置成shmflg的最小的9个bits。
- shm_segsz 被设置成 size的值。
- shm_lpid, shm_nattch, shm_atime, and shm_dtime 被设置为0
- shm_ctime 被设置成当前时间。
如果共享内存段已经存在, 如果它标识为销毁, 会检查权限。
返回值
- 如果成功,会返回一个合法的共享内存段标识符。如果出错,会返回-1, errno 来标识出错的原因。
ERRORS 如果出错,errno会被如下出错码的其中一个:
- EACCES 用户没有访问共享内存段的权限,在管理它的IPC名字空间的用户名字空间内,它没有 CAP_IPC_OWNER 能力。
- EEXIST 在shmflg中指定了IPC_CREAT 和 IPC_EXCL,但是该key对应的共享内存段已经存在。
- EINVAL 一个给定的key的内存段已经存在,但是它的size 大于已经存在的共享内存段。
- ENFILE 系统级的限制, 限制打开文件的个数是否超过了限制。
- ENOENT 给定的key不存在共享内存段, 并且没有指定IPC_CREAT。
- ENOMEM 没有足够大的内存来分配共享内存段。
- ENOSPC 所有可能的共享内存ID(SHMMNI)已经被使用,或者如果分配入参指定的size的内存段会引起超过系统级的共享内存的限制(SHMALL)。
- EPERM 指定了SHM_HUGETLB, 但是调用者没有这个权限(没有 CAP_IPC_LOCK的权限)。
遵循的协议
- POSIX.1-2001, POSIX.1-2008, SVr4.
- SHM_HUGETLB and SHM_NORESERVE are Linux extensions.
说明:
共享内存的限制:如下共享内存段资源的限制会影响到shmget()的调用:
- SHMALL System-wide limit on the total amount of shared memory, measured in units of the system page size.在linux 中,这个限制可以通过对 /proc/sys/kernel/shmall 读取和修改来获取或修改。从linux 3.16,该属性的默认值为:
ULONG_MAX - 2^24
该值的作用是对内存分配不做限制。
-
SHMMAX Maximum size in bytes for a shared memory segment.在linux, 这个限制可以通过读取或修改/proc/sys/kernel/shmmax 文件来获取。从linux 3.16 该值默认为:
ULONG_MAX - 2^24
该值的作用是对内存的分配没有限制。
-
SHMMIN Minimum size in bytes for a shared memory segment: implementation dependent (currently 1 byte, though PAGE_SIZE is the effective minimum size, 也就是说,虽然设置为1个byte, 实际上分配了一个PAGE_SIZE大小的内存)。在linux系统中该值通过 /proc/sys/kernel/shmmni读取或修改。
调用举例
https://www.cnblogs.com/fangshenghui/p/4039720.html
shmdata.h文件:
#ifndef _SHMDATA_H_HEADER
#define _SHMDATA_H_HEADER
#define TEXT_SZ 2048struct shared_use_st
{
int written;/*flag , 0: write available; not 0: read availbe;*/
char text[TEXT_SZ];/*the data*/
};
#endifshmread.c文件,共享内存读取;
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/shm.h>
#include"shmdata.h"#define MEM_KEY (1234)
int main()
{
int running =1; //judge if or not process is running
void*shm = NULL; //the addres of share memory segment
struct shared_use_st *shared;//point to shm
int shmid; //share memory id
//create share memoryshmid = shmget((key_t)MEM_KEY,sizeof(struct shared_use_st),0666|IPC_CREAT);
if(shmid ==-1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
//attach shared memory to current process namespace
shm = shmat(shmid,0,0);
if(shm ==(void*)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("\nMemory attached at %X\n",(int)shm);
//convert user defined structure data;
shared =(struct shared_use_st*)shm;
shared->written =0;
while(running)//read share memory data
{
//judge if or not this memory can read, other words, if not write process push data into the memory
if(shared->written !=0)
{
printf("You wrote: %s", shared->text);
sleep(rand()%3);
//after reading the data, set written flag is 0 for next writting
shared->written =0;
//if writing data is 'end', exit reading cycle process
if(strncmp(shared->text,"end",3)==0)
running =0;
}else//if no data input sleeping
sleep(1);
}
//dis-attach the shared memory from current process
if(shmdt(shm)==-1)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
//delete the share memory
if(shmctl(shmid, IPC_RMID,0)==-1)
{
fprintf(stderr,"shmctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}exit(EXIT_SUCCESS);
}shwrite.c 文件---共享内存写入
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/shm.h>
#include"shmdata.h"
#define MEM_KEY (1234)int main()
{
int running =1;
void*shm = NULL;
struct shared_use_st *shared = NULL;
char buffer[BUFSIZ +1];//used to save txt
int shmid;
//creat share memory segment
shmid = shmget((key_t)MEM_KEY,sizeof(struct shared_use_st),0666|IPC_CREAT);
if(shmid ==-1)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
//associate the share memory to current process namespace
shm = shmat(shmid,(void*)0,0);
if(shm ==(void*)-1)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X\n",(int)shm);
//convert to our own structure obj
shared =(struct shared_use_st*)shm;
while(running)//write data to shared memory segment
{
//if data not read, waiting for reading , and do not write txt to this share memory
while(shared->written ==1)
{
sleep(1);
printf("Waiting...\n");
}
//write data to share memory segment
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
strncpy(shared->text, buffer, TEXT_SZ);
//if written is done, set the written flag as reading available
shared->written =1;
//input end, if we finish inputing the data, and exit the cycle , and exit the process
if(strncmp(buffer,"end",3)==0)
running =0;
}
//disattach the share memory from current process
if(shmdt(shm)==-1)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
sleep(2);
exit(EXIT_SUCCESS);
}
-
shmget共享内存
2020-12-19 20:07:10与其它两种IPC机制一样,进程在使用共享内存区域以前,必须通过系统调用sys_ipc (call值为SHMGET)创建一个键值为key的共享内存对象,或获得已经存在的键值为key的某共享内存对象的引用标识符。以后对共享内存对象的...Linux为共享内存提供了四种操作。
1. 共享内存对象的创建或获得。与其它两种IPC机制一样,进程在使用共享内存区域以前,必须通过系统调用sys_ipc (call值为SHMGET)创建一个键值为key的共享内存对象,或获得已经存在的键值为key的某共享内存对象的引用标识符。以后对共享内存对象的访问都通过该引用标识符进行。对共享内存对象的创建或获得由函数sys_shmget完成,其定义如下:
int sys_shmget (key_t key, int size, int shmflg)
这里key是表示该共享内存对象的键值,size是该共享内存区域的大小(以字节为单位),shmflg是标志(对该共享内存对象的特殊要求)。
它所做的工作如下:
1) 如果key == IPC_PRIVATE,则总是会创建一个新的共享内存对象。
但是 (The name choice IPC_PRIVATE was perhaps unfortunate, IPC_NEW would more clearly show its function)
* 算出size要占用的页数,检查其合法性。
* 申请一块内存用于建立shmid_kernel数据结构,注意这里申请的内存区域大小不包括真正的共享内存区,实际上,要等到第一个进程试图访问它的时候才真正创建共享内存区。
* 根据该共享内存区所占用的页数,为其申请一块空间用于建立页表(每页4个字节),将页表清0。
* 搜索向量表shm_segs,为新创建的共享内存对象找一个空位置。
* 填写shmid_kernel数据结构,将其加入到向量表shm_segs中为其找到的空位置。
* 返回该共享内存对象的引用标识符。
2) 在向量表shm_segs中查找键值为key的共享内存对象,结果有三:
* 如果没有找到,而且在操作标志shmflg中没有指明要创建新共享内存,则错误返回,否则创建一个新的共享内存对象。
* 如果找到了,但该次操作要求必须创建一个键值为key的新对象,那么错误返回。
* 否则,合法性、认证检查,如有错,则错误返回;否则,返回该内存对象的引用标识符。
共享内存对象的创建者可以控制对于这块内存的访问权限和它的key是公开还是私有。如果有足够的权限,它也可以把共享内存锁定在物理内存中。
参见include/linux/shm.h
2. 关联。在创建或获得某个共享内存区域的引用标识符后,还必须将共享内存区域映射(粘附)到进程的虚拟地址空间,然后才能使用该共享内存区域。系统调用 sys_ipc(call值为SHMAT)用于共享内存区到进程虚拟地址空间的映射,而真正完成粘附动作的是函数sys_shmat,
其定义如下:
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
其中:
shmid是shmget返回的共享内存对象的引用标识符;
shmaddr用来指定该共享内存区域在进程的虚拟地址空间对应的虚拟地址;
shmflg是映射标志;
返回的是在进程中的虚拟地址
该函数所做的工作如下:
1) 根据shmid找到共享内存对象。
2) 如果shmaddr为0,即用户没有指定该共享内存区域在它的虚拟空间中的位置,则由系统在进程的虚拟地址空间中为其找一块区域(从1G开始);否则,就用shmaddr作为映射的虚拟地址。
(If shmaddr is NULL, the system chooses a suitable (unused) address a他 which to attach the segment)
3) 检查虚拟地址的合法性(不能超过进程的最大虚拟空间大小—3G,不能太接近堆栈栈顶)。
4) 认证检查。
5) 申请一块内存用于建立数据结构vm_area_struct,填写该结构。
6) 检查该内存区域,将其加入到进程的mm结构和该共享内存对象的vm_area_struct队列中。
共享内存的粘附只是创建一个vm_area_struct数据结构,并将其加入到相应的队列中,此时并没有创建真正的共享内存页。
当进程第一次访问共享虚拟内存的某页时,因为所有的共享内存页还都没有分配,所以会发生一个page fault异常。当Linux处理这个page fault的时候,它找到发生异常的虚拟地址所在的vm_area_struct数据结构。在该数据结构中包含有这类共享虚拟内存的一组处理程序,其中的 nopage操作用来处理虚拟页对应的物理页不存在的情况。对共享内存,该操作是shm_nopage(定义在ipc/shm.c中)。该操作在描述这个共享内存的shmid_kernel数据结构的页表shm_pages中查找发生page fault异常的虚拟地址所对应的页表条目,看共享页是否存在(页表条目为0,表示共享页是第一次使用)。如果不存在,它就分配一个物理页,并为它创建一个页表条目。这个条目不但进入当前进程的页表,同时也存到shmid_kernel数据结构的页表shm_pages中。
当下一个进程试图访问这块内存并得到一个page fault的时候,经过同样的路径,也会走到函数shm_nopage。此时,该函数查看shmid_kernel数据结构的页表shm_pages时,发现共享页已经存在,它只需把这里的页表项填到进程页表的相应位置即可,而不需要重新创建物理页。所以,是第一个访问共享内存页的进程使得这一页被创建,而随后访问它的其它进程仅把此页加到它们的虚拟地址空间。
3. 分离。当进程不再需要共享虚拟内存的时候,它们与之分离(detach)。只要仍旧有其它进程在使用这块内存,这种分离就只会影响当前的进程,而不会影响其它进程。当前进程的vm_area_struct数据结构被从shmid_ds中删除,并被释放。当前进程的页表也被更新,共享内存对应的虚拟内存页被标记为无效。当共享这块内存的最后一个进程与之分离时,共享内存页被释放,同时,这块共享内存的shmid_kernel数据结构也被释放。
系统调用sys_ipc (call值为SHMDT) 用于共享内存区与进程虚拟地址空间的分离,而真正完成分离动作的是函数sys_shmdt,其定义如下:
int sys_shmdt (char *shmaddr)
其中shmaddr是进程要分离的共享页的开始虚拟地址。
该函数搜索进程的内存结构中的所有vm_area_struct数据结构,找到地址shmaddr对应的一个,调用函数do_munmap将其释放。
在函数do_munmap中,将要释放的vm_area_struct数据结构从进程的虚拟内存中摘下,清除它在进程页表中对应的页表项(可能占多个页表项).
如果共享的虚拟内存没有被锁定在物理内存中,分离会更加复杂。因为在这种情况下,共享内存的页可能在系统大量使用内存的时候被交换到系统的交换磁盘。为了避免这种情况,可以通过下面的控制操作,将某共享内存页锁定在物理内存不允许向外交换。共享内存的换出和换入,已在第3章中讨论。
4. 控制。Linux在共享内存上实现的第四种操作是共享内存的控制(call值为SHMCTL的sys_ipc调用),它由函数sys_shmctl实现。控制操作包括获得共享内存对象的状态,设置共享内存对象的参数(如uid、gid、mode、ctime等),将共享内存对象在内存中锁定和释放(在对象的mode上增加或去除SHM_LOCKED标志),释放共享内存对象资源等。
共享内存提供了一种快速灵活的机制,它允许进程之间直接共享大量的数据,而无须使用拷贝或系统调用。共享内存的主要局限性是它不能提供同步,如果两个进程企图修改相同的共享内存区域,由于内核不能串行化这些动作,因此写的数据可能任意地互相混合。所以使用共享内存的进程必须设计它们自己的同步协议,如用信号灯等。
以下是使用共享内存机制进行进程间通信的基本操作:
需要包含的头文件:
#include
#include
#include
1.创建共享内存:
int shmget(key_t key,int size,int shmflg);
参数说明:
key:用来表示新建或者已经存在的共享内存去的关键字。
size:创建共享内存的大小。
shmflg:可以指定的特殊标志。IPC_CREATE,IPC_EXCL以及低九位的权限。
eg:
int shmid;
shmid=shmget(IPC_PRIVATE,4096,IPC_CREATE|IPC_EXCL|0660);
if(shmid==-1)
perror("shmget()");
2.连接共享内存
char *shmat(int shmid,char *shmaddr,int shmflg);
参数说明
shmid:共享内存的关键字
shmaddr:指定共享内存出现在进程内存地址的什么位置,通常我们让内核自己决定一个合适的地址位置,用的时候设为0。
shmflg:制定特殊的标志位。
eg:
int shmid;
char *shmp;
shmp=shmat(shmid,0,0);
if(shmp==(char *)(-1))
perror("shmat()\n");
3.使用共享内存
在使用共享内存是需要注意的是,为防止内存访问冲突,我们一般与信号量结合使用。
4.分离共享内存:当程序不再需要共享内后,我们需要将共享内存分离以便对其进行释放,分离共享内存的函数原形如下:
int shmdt(char *shmaddr);
5. 释放共享内存
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
*****************示例**********************
int *__accept_socketfd;
int shmid = shmget(SHAREMEMID,sizeof(int),IPC_CREAT|0666);
if (( __accept_socketfd = (int *)shmat(shmid,NULL,0 )) == (int *)-1 )
{
printf("Error:shmat\n");
return;
}
*__accept_socketfd = 0;
-
共享内存_shmget
2021-10-07 20:00:06文章目录共享内存创建共享内存映射共享内存删除共享内存父子进程共享内存共享内存通信 共享内存 共享内存是被多个...使用shmget函数创建共享内存。 使用shmat函数将创建的共享内存映射到具体的进程空间。 创建共共享内存
共享内存是被多个进程共享的一部分物理内存。一个进程向共享内存写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
如下图所示,共享内存的地址在进程A
中的地址可能是0x5000
,在进程B
中的地址可能是0x7000
,这是因为共享内存映射到不同进程当中的不同位置。
共享内存的实现分为
2
个步骤:- 使用
shmget
函数创建共享内存。 - 使用
shmat
函数将创建的共享内存映射到具体的进程空间。
创建共享内存
创建共享内存使用函数
shmget
:int shmget ( key_t key, int size, int shmflg );
key
是标识共享内存的键值,可以取非负整数
或IPC_PRIVATE
。
- 当
key
是IPC_PRIVATE
时,shmflg
不需要IPC_CREAT
。 - 当
key
是非负整数
时,shmflg
需要IPC_CREAT
。
size
是共享内存的大小,以字节为单位。shmflg
是权限标志,与文件的读写权限一样。
如果函数执行成功,则返回共享内存标识符,否则返回
-1
。映射共享内存
映射共享内存使用函数
shmat
:int shmat ( int shmid, char *shmaddr, int flag );
shmid
:shmget
函数返回的共享内存标识符。shmaddr
:通常为0
。flag
:通常为0
。
如果函数执行成功,则返回共享内存映射到进程中的地址,否则返回
-1
。删除共享内存
当一个进程不再需要共享内存时,需要把它从进程地址空间中删除:
int shmdt ( char *shmaddr );
参数
shmaddr
是从shmat
中获得的。父子进程共享内存
代码实例:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/shm.h> #include <sys/wait.h> #define PERM (S_IRUSR | S_IWUSR) int main ( int argc, char **argv ) { int shmid; char *p_addr, *c_addr; if ( argc != 2 ) { fprintf ( stderr, "Usage: %s\n", argv[0] ); exit ( 1 ); } if ( ( shmid = shmget ( IPC_PRIVATE, 1024, PERM ) ) == -1 ) { /* 创建共享内存 */ fprintf ( stderr, "Create Share Memory Error: %s\n", strerror ( errno ) ); exit ( 1 ); } if ( fork() ) { /* 父进程写 */ p_addr = ( char * ) shmat ( shmid, NULL, 0 ); memset ( p_addr, '\0', 1024 ); strncpy ( p_addr, argv[1], 1024 ); wait ( NULL ); exit ( 0 ); } else { /* 子进程读 */ sleep ( 1 ); /* 暂停1秒 */ c_addr = ( char * ) shmat ( shmid, NULL, 0 ); printf ( "Client get %s\n", c_addr ); exit ( 0 ); } }
执行结果:
$ ./my_test 12345678 Client get 12345678
共享内存通信
shm_com.h
如下:#ifndef __SHM_COM__ #define __SHM_COM__ #define TEXT_SZ 2048 struct shared_use_st { int written_by_you; char some_text[TEXT_SZ]; }; #endif
shmread.c
如下:#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "shm_com.h" int main ( void ) { int running = 1; void *shared_memory = NULL; struct shared_use_st *shared_stuff; int shmid = shmget ( ( key_t ) 1234, sizeof ( struct shared_use_st ), 0666 | IPC_CREAT ); if ( shmid == -1 ) { fprintf ( stderr, "shmget failed\n" ); exit ( EXIT_FAILURE ); } shared_memory = shmat ( shmid, NULL, 0 ); /* 映射共享内存 */ if ( shared_memory == ( void * ) -1 ) { fprintf ( stderr, "shmat failed\n" ); exit ( EXIT_FAILURE ); } printf ( "Memory attached at %p\n", shared_memory ); /* 让结构体指针指向这块共享内存 */ shared_stuff = ( struct shared_use_st * ) shared_memory; shared_stuff->written_by_you = 0; /* 控制读写顺序 */ while ( running ) { /* 循环的从共享内存中读数据,直到读到“end” */ if ( shared_stuff->written_by_you ) { printf ( "You wrote: %s", shared_stuff->some_text ); sleep ( 1 ); /* 读进程睡一秒,同时会导致写进程睡一秒,这样做到读了之后再写 */ shared_stuff->written_by_you = 0; if ( strncmp ( shared_stuff->some_text, "end", 3 ) == 0 ) { running = 0; /* 结束循环 */ } } } if ( shmdt ( shared_memory ) == -1 ) { /* 删除共享内存 */ fprintf ( stderr, "shmdt failed\n" ); exit ( EXIT_FAILURE ); } exit ( EXIT_SUCCESS ); }
shmwrite.c
如下:#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include "shm_com.h" int main ( void ) { int running = 1; void *shared_memory = NULL; struct shared_use_st *shared_stuff; char buffer[BUFSIZ]; int shmid = shmget ( ( key_t ) 1234, sizeof ( struct shared_use_st ), 0666 | IPC_CREAT ); if ( shmid == -1 ) { fprintf ( stderr, "shmget failed\n" ); exit ( EXIT_FAILURE ); } shared_memory = shmat ( shmid, NULL, 0 ); /* 映射共享内存 */ if ( shared_memory == ( void * ) -1 ) { fprintf ( stderr, "shmat failed\n" ); exit ( EXIT_FAILURE ); } printf ( "Memory attached at %p\n", shared_memory ); /* 让结构体指针指向这块共享内存 */ shared_stuff = ( struct shared_use_st * ) shared_memory; while ( running ) { /* 循环地向共享内存中写数据 */ while ( shared_stuff->written_by_you == 1 ) { sleep ( 1 ); /* 等到读进程读完之后再写 */ printf ( "waiting for client...\n" ); } printf ( "Enter some text: " ); fgets ( buffer, BUFSIZ, stdin ); strncpy ( shared_stuff->some_text, buffer, TEXT_SZ ); shared_stuff->written_by_you = 1; if ( strncmp ( buffer, "end", 3 ) == 0 ) { running = 0; /* 结束循环 */ } } if ( shmdt ( shared_memory ) == -1 ) { /* 删除共享内存 */ fprintf ( stderr, "shmdt failed\n" ); exit ( EXIT_FAILURE ); } exit ( EXIT_SUCCESS ); }
- 使用
-
共享内存的常用函数详解shmget shmat
2020-12-19 20:07:08对共享内存对象的创建或获得由函数sys_shmget完成,其定义如下: int sys_shmget (key_t key, int size, int shmflg) 这里key是表示该共享内存对象的键值,size是该共享内存区域的大小(以字节为单位),shmflg是... -
unix中共享内存(shmget的实现,非mmap)
2021-05-23 04:40:54共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区。在/proc/sys/kernel/目录下,记录着...一、应用共享内存的使用,主要有以下几个API:ftok()、shmget()、shmat()、shmdt()及shmctl()。1)用ftok... -
共享内存 mmap shmget 区别
2020-12-19 20:06:59下面是几个我认为介绍的还不错的 : ) 初学的同学多半都会想横向对比一下,到底用mmap实现共享内存好呢,还是用shmget好啊? 下面是我个人的一些理解: 1. 二者本质上是类似的,mmap可以看到文件的实体,而 shmget ... -
C语言之共享内存之shmget进程间通信(二十三)
2021-09-21 14:03:42一、 shm_open()和shmget()区别 1.shm_open主要打开一个共享内存用户进程间交换大量数据。 用法: 把共享内存以文件方式打开,这样就可以直接向文件中写入数据. 2.shmget:共享内存用于进程间通信。共享内存函数由... -
shmget()函数:
2021-10-19 16:44:34int shmget( key_t, size_t, flag); 3,函数参数: 4,返回值: 成功:返回共享内存的标识符,失败返回-1,错误原因存于errno中 错误代码: EINVAL:参数size小于SHMMIN或大于SHMMAX EEXIST:预建立key所指的共享... -
共享内存 shmget函数
2021-03-07 19:38:04int shmget( key_t key, size_t size, int flag ); //such as: key_t key = ftok(".",1); shmId = shmget(key,1024*4,IPC_CREAT|0666); if(shmId == -1){ perror("shmget:"); return -1; } 第一个参数 k -
mmap内存映射和shmget共享内存
2019-06-14 12:41:173、另外mmap有一个好处是当机器重启,因为mmap把文件保存在磁盘上,这个文件还保存了操作系统同步的映像,所以mmap不会丢失,但是shmget就会丢失。 --------------------- 作者:hj605635529 来源:CSDN 原文... -
Linux API-共享内存:shmget、shmat、shmdt、shmctl
2021-02-16 11:45:57shmget——创建/打开共享内存 shmat——将共享内存与当前进程相关联 shmdt——将当前进程与共享内存间脱离关联 shmctl——操控共享内存 一、shmget——创建/打开共享内存 1.原函数 表头文件 #include <sys/ipc.h... -
linux中shmget参数详解
2020-03-31 17:36:24#include <...int shmget (key_t key, size_t size, int shmflg); key_t key key标识共享内存的键值: 0/ IPC_PRIVATE 。 当key的取值为IPC_PRIVATE ,则函数shmget()将创建一块新的 共享内存; ... -
Linux_进程间通信 共享内存shmget方式详解
2011-12-18 09:58:42Linux_进程间通信_-_共享内存shmget方式 -
linuxC 共享内存实例(shmget和mmap)
2021-11-11 18:26:27shmid = shmget((key_t)1000, sizeof(int), 0666|IPC_CREAT); if (shmid == -1) { return 0; } shm = shmat(shmid, 0, 0); if (shm == (void*)-1) { return 0; } memset(&data, 0x00, sizeof(int)); data = 110; *... -
编程了解共享内存--mmap和shmget两种方式实现
2019-09-07 16:44:35shmid = shmget((key_t)1234, sizeof(struct Shared_BUF), 0644|IPC_CREAT); if (shmid == -1) { fprintf(stderr, "shmat failed\n"); return -1; } // 将共享内存连接到当前进程的地址空间 shm = shmat... -
Linux IPC 共享内存 ,System V 共享内存机制: shmget,shmat,shmdt,shmctl
2020-03-14 19:49:06共享内存机制 System V 共享内存机制 ftok()函数 ftok.c shmget()函数 shmget.c shmat()函数 shmat.c shmdt()函数 shmdt.c shmctl()函数 shmctl_ipc_state.c shmctl_ipc_set.c shmctl_ipc_rmid.c shmat_fork_read_... -
linux系统编程--shmget shmat shmdt
2021-05-12 00:48:44开辟一块共享内存 shmget()2.允许本进程使用共某块共享内存 shmat()3.写入/读出4.禁止本进程使用这块共享内存 shmdt()5.删除这块共享内存 shmctl()或者命令行下ipcrmftok()。它有两个参数,一个是字符串,一个是字符... -
6.Linux进程间通信:共享内存 shmget()、shmat()、shmdt()、shmctl()
2020-08-04 14:13:39不相关的进程可以通过该函数的返回值访问同一共享内存,它代表程序可能要使用的某个资源,程序对所有共享内存的访问都是间接的,程序先通过调用shmget()函数并提供一个键,再由系统生成一个相应的共享内存标识符... -
linux中shmget函数
2018-01-26 11:21:23shmget int shmget(key_t key, size_t size, int flag); key: 标识符的规则 size:共享存储段的字节数 flag:读写的权限 返回值:成功返回共享存储的id,失败返回-1 key_t key --------------------------... -
c语言shmget shmctl共享内存操作
2022-01-19 13:52:54shmid=shmget(key,2048,SHM_R|SHM_W); if(shmid) { perror("shmat"); exit(-1); } else { printf("delete shared-memory\n"); } shmctl(shmid,IPC_RMID,NULL); system("ipcs -m"); return 0; } -
共享内存函数(shmget、shmat、shmdt、shmctl)及其范例
2020-03-31 21:22:55共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。 shmget函数原型 shmget(得到一个共享内存标识符或创建一个共享内存对象) 所需头文件 #include <... -
共享内存函数(shmget、shmat、shmdt、shmctl)及其范例 - guoping16的专栏 - 博客频道 - CSDN
2021-05-23 04:40:482014年4月2日共享内存函数(shmget、shmat、shmdt、shmctl)及其范例 - guoping16的专栏 - 博客频道 - http://doc.xuehai.net登录 | 注册guoping16的专栏目录视图摘要视图订阅个人资料2014开源技术大会(读书汇) ... -
共享内存函数(shmget、shmat、shmdt、shmctl)
2021-09-03 10:38:21一:shmget函数:得到一个共享内存标识符或创建一个共享内存对象 1,头文件: #include <sys/ipc.h> #include <sys/shm.h> 2,函数说明: 得到一个共享内存标识符或创建一个共享内存对象并返回共享... -
linux - 在Linux x86-64上使用mmap或shmget分配非默认的大页面 - 堆栈内存溢出
2021-05-17 19:47:43我一直试图从非默认的大页面池中获取shmget和mmap进行分配,但在内核4.13.0-32-generic上却没有成功。 我已经配置了2M和1G大型页面。 使用1G页面作为默认大小,此调用将成功:addr = mmap(0, byteAmoun... -
linux共享内存shmget函数踩坑:
2020-09-11 17:11:33linux共享内存shmget函数踩坑: 【声明】int shmget(key_t key,size_t size,int shmflg); 【说明】key_t本质为int类型 【问题】shmget返回-1 【原因】size大小不合理 size大小不能超过系统指定共享内存的最大值... -
LinuxC: 共享内存 ftok() shmget() shmat() shmdt() shmctl()
2021-08-22 02:27:50共享内存是最快的IPC Linux命令【ipcs】可查看共享内存信息 Linux命令【ipcrm -m shmid】删除shmid的值的共享内存 #include <sys/ipc.h> #include <...int shmget(key_t key, size_t size, in.