对于共享内存的知识点介绍,大家可以参阅下面这两篇文章:
共享内存基础知识01
共享内存基础知识02
注意:
如果在代码中没有手动删除,共享内存并不会随着程序的终止而自动清理!
大家可以使用shell命令:ipcs -m 查看自己的共享内存区。效果如下图所示:
其中:
第一列就是共享内存的key;
第二列是共享内存的编号shmid;
第三列就是创建的用户owner;
第四列就是权限perms;
第五列为创建的大小bytes;
第六列为连接到共享内存的进程数nattach;
第七列是共享内存的状态status。其中显示“dest”表示共享内存段已经被删除,但是还有用户在使用它,当该段内存的mode字段设置为SHM_DEST时就会显示“dest”。当用户调用shmctl的IPC_RMID时,内存先查看多少个进程与这个内存关联着,如果关联数为0,就会销毁这段共享内存,否者设置这段内存的mod的mode位为SHM_DEST,如果所有进程都不用则删除这段共享内存。
图中所有者为root的共享内存区是我刚才创建的,我们来查看一下这段共享内存的具体信息:输入shell命令:ipcs -m -i 2654237
如果程序中没有删除它,此时,我们可以使用shell命令:ipcrm shmid 来删除指定共享内存区。(示例:ipcrm 2654237)
大家可以通过 man ipcs 查看其更多用法。
下面是自己写的一个示例。详细介绍了使用共享内存的主要步骤,以及对共享内存进行操作之前,使用信号量机制进行同步保护。当然,大家也可以使用记录锁来进行同步。
server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/sem.h>
#define IPCKEY 0x19890319 //为增强可移植性,自定义key_t
#ifdef _SEM_SEMUN_UNDEFINED //关于信号量的知识,可以查看我的前一篇文章
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
#endif
void my_err(char *);
int semphore_p(int);
int semphore_v(int);
int main(void)
{
printf("----------Start----------\n");
int shm_id;
void *addr;
int page_size=getpagesize(); //Get memory page size
if((shm_id=shmget(IPCKEY,page_size,0640|IPC_CREAT|IPC_EXCL))==-1) //注意:共享内存区段大小必须为当前系统架构页面大小的整数倍。否则,系统自动扩充至整数倍,但是最后一页的剩余空间将无法访问。
my_err("shmget error");
addr=shmat(shm_id,0,0); // Attach shared memory
if(addr==(void *)-1)
my_err("shmat error");
//在对共享内存操作前,使用信号量进行保护同步,避免多个进程同时操作。
int sem_id;
union semun semun_val;
if((sem_id=semget(IPCKEY,1,IPC_CREAT))==-1)
my_err("semget error");
semun_val.val=1;
if(semctl(sem_id,0,SETVAL,semun_val)==-1)
my_err("semctl set error");
if(semphore_p(sem_id)==-1) // 信号量P操作
my_err("semphore_p error");
strncpy(addr,"test share memory.",18); //对共享内存区进行操作。You can do something else.
printf("write into shm ok\n");
sleep(10);
if(semphore_v(sem_id)==-1) //信号量V操作
my_err("semphore_v error");
if(shmdt(addr)==-1) //Detach shared memory
my_err("shmdt error");
if(shmctl(shm_id,IPC_RMID,NULL)==-1) //Remove shared memory
my_err("shmctl error");
printf("shm removed,process end\n");
exit(0);
}
void my_err(char *str)
{
perror(str);
exit(1);
}
int semphore_p(int semid)
{
struct sembuf _sembuf;
_sembuf.sem_num=0;
_sembuf.sem_op=-1;
_sembuf.sem_flg=SEM_UNDO;
if(semop(semid,&_sembuf,1)==-1)
return -1;
return 0;
}
int semphore_v(int semid)
{
struct sembuf _sembuf;
_sembuf.sem_num=0;
_sembuf.sem_op=1;
_sembuf.sem_flg=SEM_UNDO;
if(semop(semid,&_sembuf,1)==-1)
return -1;
return 0;
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define IPCKEY 0x19890319
#ifdef _SEM_SEMUN_UNDEFINED
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
#endif
void my_err(char *);
int semphore_p(int);
int semphore_v(int);
int main(void)
{
printf("----------client start------------\n");
int shm_id;
void *addr;
int page_size=getpagesize();
if((shm_id=shmget(IPCKEY,page_size,0640))==-1)
my_err("shmget error");
addr=shmat(shm_id,0,0);
if(addr==(void *)-1)
my_err("shmat error");
int sem_id;
if((sem_id=semget(IPCKEY,1,0))==-1)
my_err("semget error");
if(semphore_p(sem_id)==-1)
my_err("semphore_p error");
printf("server msg:%s\n",addr);
if(semphore_v(sem_id)==-1)
my_err("semphore_v error");
if(shmdt(addr)==-1)
my_err("shmdt error");
printf("end\n");
exit(0);
}
void my_err(char *str)
{
perror(str);
exit(1);
}
int semphore_p(int semid)
{
struct sembuf _sembuf;
_sembuf.sem_num=0;
_sembuf.sem_op=-1;
_sembuf.sem_flg=SEM_UNDO;
if(semop(semid,&_sembuf,1)==-1)
return -1;
return 0;
}
int semphore_v(int semid)
{
struct sembuf _sembuf;
_sembuf.sem_num=0;
_sembuf.sem_op=1;
_sembuf.sem_flg=SEM_UNDO;
if(semop(semid,&_sembuf,1)==-1)
return -1;
return 0;
}