对于共享内存的知识点介绍,大家可以参阅下面这两篇文章:
共享内存基础知识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; }
#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; }