共享内存函数(shmget、shmat、shmdt、shmctl)及其范例
共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。下⾯的表格列出了这四个函数的函数原型及其具体说明。
1. shmget函数原型
shmget(得到⼀个共享内存标识符或创建⼀个共享内存对象)
所需头⽂件#include <sys/ipc.h> #include <sys/shm.h>
write的返回值函数
说明
得到⼀个共享内存标识符或创建⼀个共享内存对象并返回共享内存标识符
函数
原型
int shmget(key_t key, size_t size, int shmflg)
函数传⼊值key
0(IPC_PRIVATE):会建⽴新共享内存对象
⼤于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值
size
⼤于0的整数:新建的共享内存⼤⼩,以字节为单位
0:只获取共享内存时指定为0
shmflg
0:取共享内存标识符,若不存在则函数会报错
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建⼀个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建⼀个消息队列;如果存在这样的共享内存则报错
函数返回值成功:返回共享内存的标识符出错:-1,错误原因存于error中
附加说明上述shmflg参数为模式标志参数,使⽤时需要与IPC对象存取权限(如0600)进⾏|运算来确定信号量集的存取权限
错误代码EINVAL:参数size⼩于SHMMIN或⼤于SHMMAX
EEXIST:预建⽴key所指的共享内存,但已经存在
EIDRM:参数key所指的共享内存已经删除
ENOSPC:超过了系统允许建⽴的共享内存的最⼤值(SHMALL) ENOENT:参数key所指的共享内存不存在,⽽参数shmflg未设IPC_CREAT位EACCES:没有权限
ENOMEM:核⼼内存不⾜
在Linux环境中,对开始申请的共享内存空间进⾏了初始化,初始值为0x00。
如果⽤shmget创建了⼀个新的消息队列对象时,则shmid_ds结构成员变量的值设置如下:Ÿ shm_lpid、shm_nattach、shm_atime、shm_dtime设置为0。
Ÿ msg_ctime设置为当前时间。
Ÿ shm_segsz设成创建共享内存的⼤⼩。
Ÿ shmflg的读写权限放在de中。
Ÿ shm_perm结构的uid和cuid成员被设置成当前进程的有效⽤户ID,gid和cuid成员被设置成当前进程的有效组ID。
2. shmat函数原型
shmat(把共享内存区对象映射到调⽤进程的地址空间)
所需头⽂件#include <sys/types.h> #include <sys/shm.h>
函数说明连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调⽤进程的地址空间,随后可像本地空间⼀样访问
函数原
型
void *shmat(int shmid, const void *shmaddr, int shmflg)
函数传⼊值msqid共享内存标识符
shmaddr
指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核⾃⼰决定⼀个合适的地址位置
shmflg SHM_RDONLY:为只读模式,其他为读写模式
函数返回值成功:附加好的共享内存地址出错:-1,错误原因存于error中
附加说明fork后⼦进程继承已连接的共享内存地址。exec后该⼦进程与已连接的共享内存地址⾃动脱离(detach)。进程结束后,已连接的共享内存地址会⾃动脱离(detach)
错误代码EACCES:⽆权限以指定⽅式连接共享内存EINVAL:⽆效的参数shmid或shmaddr ENOMEM:核⼼内存不⾜
3. shmdt函数原型shmat(断开共享内存连接)
所需头⽂件#include <sys/types.h> #include <sys/shm.h>
函数说明与shmat函数相反,是⽤来断开与共享内存附加点的地址,禁⽌本进程访问此⽚共享内存函数原型int shmdt(const void *shmaddr)
函数传⼊
值
shmaddr:连接的共享内存的起始地址
函数返回值成功:0
出错:-1,错误原因存于error中
附加说明本函数调⽤并不删除所指定的共享内存区,⽽只是将先前⽤shmat函数连接(attach)好的共享内存脱离(detach)⽬前的进程
错误代码EINVAL:⽆效的参数shmaddr
4. shmctl函数原型
shmctl(共享内存管理)
所需头⽂件#include <sys/types.h> #include <sys/shm.h>
函数说明完成对共享内存的控制
函数原型int shmctl(int shmid, int cmd, struct shmid_ds *buf)
函数传⼊值msqid共享内存标识符
cmd
IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
IPC_RMID:删除这⽚共享内存
buf共享内存管理结构体。具体说明参见共享内存内核结构定义部分
函数返回值成功:0
出错:-1,错误原因存于error中
错误代码EACCESS:参数cmd为IPC_STAT,确⽆权限读取该共享内存EFAULT:参数buf指向⽆效的内存地址
EIDRM:标识符为msqid的共享内存已被删除
EINVAL:⽆效的参数cmd或shmid
EPERM:参数cmd为IPC_SET或IPC_RMID,却⽆⾜够的权限执⾏
共享内存应⽤范例
5. ⽗⼦进程通信范例
⽗⼦进程通信范例,shm.c源代码如下:#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>
#define SIZE 1024
int main()
{
int shmid ;
char *shmaddr ;
struct shmid_ds buf ;
int flag = 0 ;
int pid ;
shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ;
if ( shmid < 0 )
{
perror("get shm ipc_id error") ;
return -1 ;
}
pid = fork() ;
if ( pid == 0 )
{
shmaddr = (char *)shmat( shmid, NULL, 0 ) ;
if ( (int)shmaddr == -1 )
{
perror("shmat addr error") ;
return -1 ;
}
strcpy( shmaddr, "Hi, I am child process!\n") ;
shmdt( shmaddr ) ;
return 0;
} else if ( pid > 0) {
sleep(3 ) ;
flag = shmctl( shmid, IPC_STAT, &buf) ;
if ( flag == -1 )
{
perror("shmctl shm error") ;
return -1 ;
}
printf("shm_segsz =%d bytes\n", buf.shm_segsz ) ;
printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid ) ; printf("chlid pid=%d, shm_lpid = %d \n",pid , buf.shm_lpid ) ;
shmaddr = (char *) shmat(shmid, NULL, 0 ) ;
if ( (int)shmaddr == -1 )
{
perror("shmat addr error") ;
return -1 ;
}
printf("%s", shmaddr) ;
shmdt( shmaddr ) ;
shmctl(shmid, IPC_RMID, NULL) ;
}else{
perror("fork error") ;
shmctl(shmid, IPC_RMID, NULL) ;
}
return 0 ;
}
编译 gcc shm.c –o shm。
执⾏ ./shm,执⾏结果如下:
shm_segsz =1024 bytes
shm_cpid = 9503
shm_lpid = 9504
Hi, I am child process!
6. 多进程读写范例
多进程读写即⼀个进程写共享内存,⼀个或多个进程读共享内存。下⾯的例⼦实现的是⼀个进程写共享内存,⼀个进程读共享内存。
(1)下⾯程序实现了创建共享内存,并写⼊消息。
shmwrite.c源代码如下:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
typedef struct{
char name[8];
int age;
} people;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论