1.共享内存
(1)关于进程间的用到的两个命令:
1.ipcs命令
- ipcs -s 信号量
- ipcs -m 共享内存
- ipcs -q 消息队列
2.ipcrm命令
- ipcrm -s id:删除信号量
- ipcrm -m id:删除共享内存
- ipcrm -q id:删除消息队列
(2)共享内存工作原理
箭头显示了每个进程的逻辑地址空间到可用物理内存的映射关系
3.共享内存的解释
示意图:
sem.h
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/sem.h>
#include<sys/shm.h>
union semun
{
int val;
};
void sem_init();
void sem_p(int index);
void sem_v(int index);
void sem_destroy();
sem.c
#include "sem.h"
#define SEM_NUM 2
static int semid = -1;
int sem_init()
{
//创建
semid = semget((key_t)1234,SEM_NUM,IPC_CREAT|IPC_EXCL|0600);
//如果全新创建成功的信号量等于-1,则失败
if( semid == -1)
{
perror("semget error");
return -1;
}
else
{
//如果全新创建成功,初始化
int a[SEM_NUM] = {1,0};
union semun semval;
int i = 0;
for(;i<SEM_NUM;i++)
{
semval.val = a[i];
if(semctl(semid,i,SETVAL,semval) == -1)
{
perror("semctl setval error");
return -1;
}
}
}
return 0;
}
int sem_p(int index)
{
//判断传进来的值
if(index < 0|| index >= SEM_NUM)
{
printf("sem_p:index arg error\n");
return -1;
}
//合法,定义结构体
struct sembuf buf;
buf.sem_num = index;
buf.sem_op = -1;//p
buf.sem_flg = SEM_NUDO;
if(semop(semid,&buf,1) == -1)
{
perror("semop p error");
return -1;
}
}
int sem_v(int index)
{
if(index < 0|| index >= SEM_NUM)
{
printf("sem_v:index arg error\n");
return -1;
}
//合法,定义结构体
struct sembuf buf;
buf.sem_num = index;
buf.sem_op = 1;//p
buf.sem_flg = SEM_NUDO;
if(semop(semid,&buf,1) == -1)
{
perror("semop v error");
return -1;
}
}
void sem_destroy();
{
if (semctl(semid ,0 ,IPC_RMID) == -1)
{
perror("semctl rm error");
}
}
4.所用到的函数
1.创建共享内存shmget函数
shmget(得到一个共享内存标识符或创建一个共享内存对象)
- 所需头文件:
#include <sys/ipc.h>
#include <sys/shm.h> - 函数原型
int shmget(key_t key, size_t size, int shmflg) - 函数传入值
- 函数返回值
成功:返回共享内存的标识符
出错:-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的读写权限放在shm_perm.mode中。
shm_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
- shmat函数原型(把共享内存区对象映射到调用进程的地址空间)
- 头文件
#include <sys/types.h>
#include <sys/shm.h> - 函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg) - 函数传入值
- 函数返回值
成功:附加好的共享内存地址
出错:-1,错误原因存于error中 - 附加说明
fork后子进程继承已连接的共享内存地址。exec后该子进程与已连接的共享内存地址自动脱离(detach)。进程结束后,已连接的共享内存地址会自动脱离(detach)
错误代码
EACCES:无权限以指定方式连接共享内存
EINVAL:无效的参数shmid或shmaddr
ENOMEM:核心内存不足
3.shmdt函数(断开共享内存连接,与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存)
- 头文件
#include <sys/types.h>
#include <sys/shm.h> - 函数原型
int shmdt(const void *shmaddr) - 函数传入值
- 附加说明
本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程
错误代码
EINVAL:无效的参数shmaddr
4 shmctl函数原型(共享内存管理)
- 头文件
#include <sys/types.h>
#include <sys/shm.h> - 函数原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf) - 函数传入值
- 函数返回值
成功:0
出错:-1,错误原因存于error中 - 错误代码
EACCESS:参数cmd为IPC_STAT,确无权限读取该共享内存
EFAULT:参数buf指向无效的内存地址
EIDRM:标识符为msqid的共享内存已被删除
EINVAL:无效的参数cmd或shmid
EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行