struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t shm_segsz; /* Size of segment (bytes) */
time_t shm_atime; /* Last attach time */
time_t shm_dtime; /* Last detach time */
time_t shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; /* No. of current attaches */
...
};
#include
#include
int shmget(key_t key, size_t size, int flag);
//返回值:成功返回共享存储ID;出错返回-1
参数:
- key、flag:如何设置见文章==>https://blog.csdn.net/qq_41453285/article/details/90552522
- size:如果此函数用来创建一个共享存储,那么此参数指定共享存储的长度,单位为“字节”,段内的内容全部初始化为0。如果此函数用来引用一个已存在的共享存储,那么此参数指定为0
size参数的注意事项:
- size通常将其向上取为系统页长的整倍数。如果指定的size值并非系统页长的整数倍,那么最后一页的余下部分是不可使用的
如果此函数用来创建一个新的共享存储,那么内核会自动初始化共享存储struct shmid_ds结构体,初始化结果如下:
#include
#include
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
//返回值:成功返回0;失败返回-1
cmd参数:
- 此参数对应如下,此参数对shmid指向的共享存储进行多种不同操作
#include
#include
void *shmat(int shmid, const void *addr, int flag);
//返回值:成功,返回指向共享存储段的指针;出错返回(void*)-1
共享存储段连接到调用进程的哪个地址上与addr参数以及flag中是否指定SHM_RND有关:
addr参数:
- 如果addr为0:则此函数连接到由内核选择的共享存储段的第一个可用地址上。这是推荐的使用方法
- 如果addr非0:并且没有指定SHM_RND,则此段连接到参数addr所指定的地址上
- 如果addr非0:并且指定了SHM_RND,则此段连接到(addr-(addr mod SHMLBA))所表示的地址上,该算式是将地址向下去最近1个SHMLBA的倍数
flag参数:
- SHM_RND:意思是“取整”
- SHMLBA:意思是“地边界地址倍数”,它总是2的乘方
- SHM_RDONLY:则以只读方式连接此段,否则以读写方式连接此段
#include
#include
int shmdt(const void *shmaddr);
//返回值:成功,返回0;出错返回-1
#include
#include
#include
#include
#include
#define ARRAY_SIZE 40000
#define MALLOC_SIZE 100000
#define SHM_SIZE 100000
#define SHM_MODE 0600
char array[ARRAY_SIZE];
int main()
{
int shmid;
char *ptr,*shmptr;
if((ptr=malloc(MALLOC_SIZE))==NULL){
perror("malloc");
exit(EXIT_FAILURE);
}
if((shmid=shmget(IPC_PRIVATE,SHM_SIZE,SHM_MODE))==-1){
perror("shmget");
exit(EXIT_FAILURE);
}
if((shmptr=shmat(shmid,0,0))==(void*)-1){
perror("shmat");
exit(EXIT_FAILURE);
}
printf("arrar[] from %p to %p\n",(void*)&array[0],(void*)&array[ARRAY_SIZE]);
printf("stack around %p\n",(void*)&shmid);
printf("malloc from %p to %p\n",(void*)ptr,(void*)(ptr+MALLOC_SIZE));
printf("share memory attached from %p to %p\n",(void*)shmptr,(void*)(shmptr+SHM_SIZE));
if(shmctl(shmid,IPC_RMID,0)==-1){
perror("shmctl");
exit(EXIT_FAILURE);
}
exit(0);
}
//A_3_shm_A.c
#include
#include
#include
#include
#include
#define SHM_SIZE 512
#define FLAG IPC_CREAT|0777
#define SHMID 100
#define SEMID 100
#define SHMFILENAME "./shm.txt"
#define SEMFILENAME "./sem.txt"
key_t createKey(char *name,int id);
void create_sem_and_wait();
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
int main()
{
int shmId;
char *shmptr;
key_t key;
key=createKey(SHMFILENAME,SHMID);
//创建共享存储
if((shmId=shmget(key,SHM_SIZE,FLAG))==-1){
printf("A shmget error\n");
exit(EXIT_FAILURE);
}
//以只读的方式连接到共享存储,并且shmptr引用到共享存储的地址上
if((shmptr=shmat(shmId,0,SHM_RDONLY))==(void*)-1){
printf("A shmat error\n");
exit(EXIT_FAILURE);
}
printf("wait...\n");
//创建信号量并且等待信号量的值变为0
create_sem_and_wait();
printf("The content of the Shared memory is:%s\n",shmptr);
//分离共享存储
if(shmdt(shmptr)==-1){
printf("A shmdt error\n");
exit(EXIT_FAILURE);
}
//消除共享内存
if(shmctl(shmId,IPC_RMID,NULL)==-1){
printf("A shmctl error\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
key_t createKey(char *name,int id)
{
key_t key;
if((key=ftok(name,id))==-1){
printf("A ftok error\n");
exit(EXIT_FAILURE);
}
return key;
}
void create_sem_and_wait()
{
key_t key;
int semId;
key=createKey(SEMFILENAME,SEMID);
//创建信号量集合,集合中只有1个信号量(ID为0)
if((semId=semget(key,1,IPC_CREAT|0777))==-1){
printf("A semget error\n");
exit(EXIT_FAILURE);
}
//设置信号量集合中ID为0的信号量的值为1
union semun arg;
arg.val=1;
if(semctl(semId,0,SETVAL,arg)==-1){
printf("A semctl error\n");
exit(EXIT_FAILURE);
}
//获得当前信号量集合中ID为0的信号量值
/*int semval;
if((semval=semctl(semId,0,GETVAL,NULL))==-1){
printf("A semctl error\n");
exit(EXIT_FAILURE);
}
printf("current semval:%d\n",semval);*/
//等待信号量集合中ID为0的信号量值变为0
struct sembuf buff;
buff.sem_num=0;
buff.sem_op=0;
buff.sem_flg=0;
if(semop(semId,&buff,1)==-1){
printf("A semop error\n");
exit(EXIT_FAILURE);
}
//销毁信号量集合
if(semctl(semId,0,IPC_RMID,NULL)==-1){
printf("A semctl error\n");
exit(EXIT_FAILURE);
}
}
////A_3_shm_B.c
#include
#include
#include
#include
#include
#include
#define SHM_SIZE 512
#define FLAG 0666
#define SHMFILENAME "./shm.txt"
#define SEMFILENAME "./sem.txt"
#define SHMID 100
#define SEMID 100
key_t createKey(char* filename,int id);
void signal_sem();
int main()
{
int shmId;
char *shmptr;
char buff[]="B writes something to the shared memory";
key_t key;
key=createKey(SHMFILENAME,SHMID);
//引用共享存储
if((shmId=shmget(key,0,FLAG))==-1){
printf("B shmget error\n");
exit(EXIT_FAILURE);
}
//获取共享存储首地址
if((shmptr=shmat(shmId,(void*)0,SHM_RND))==(void*)-1){
printf("B shmat error\n");
exit(EXIT_FAILURE);
}
//向共享存储写入内容
bcopy(buff,shmptr,sizeof(buff));
//分离共享内存
if(shmdt(shmptr)==-1){
printf("B shmdt error\n");
exit(EXIT_FAILURE);
}
signal_sem();
exit(EXIT_SUCCESS);
}
key_t createKey(char* filename,int id)
{
key_t key;
if((key=ftok(filename,id))==-1){
printf("B ftok error\n");
exit(EXIT_FAILURE);
}
return key;
}
void signal_sem()
{
int semId;
key_t key;
key=createKey(SEMFILENAME,SEMID);
//引用信号量集合
if((semId=semget(key,0,0777))==-1){
printf("B semget error\n");
exit(EXIT_FAILURE);
}
//获得当前信号量集合中ID为0的信号量值
/*int semval;
if((semval=semctl(semId,0,GETVAL,NULL))==-1){
printf("A semctl error\n");
exit(EXIT_FAILURE);
}
printf("current semval:%d\n",semval);*/
//将信号量集合中信号量ID为0的信号量值变为0
struct sembuf buff;
buff.sem_num=0;
buff.sem_op=-1;
buff.sem_flg=0;
if(semop(semId,&buff,1)==-1){
printf("B semop error\n");
exit(EXIT_FAILURE);
}
}