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 2048
struct shared_use_st
{
int written;/*flag , 0: write available; not 0: read availbe;*/
char text[TEXT_SZ];/*the data*/
};
#endif
shmread.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 memory
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);
}
//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);
}