共享内存
共享内存是Lunix系统中最底层的通信机制,也是最快的通信机制。共享内存通过两个或多个进程共享同一块内存区域来实现进程间的通信,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。通常是由一个进程创建一块共享内存区域,然后多个进程可以对其进行访问,一个进程将要传出的数据存放到共享内存中,另一个或多个进程则直接从共享内存中读取数据。因此这种通信方式是最高效的进程间通信方式。但实际的问题在于,当两个或多个进程使用共享内存进行通信时,同步问题的解决显得尤为重要,否则就会造成因不同进程同时读写一块共享内存中的数据而发生混乱。在通常的情况下,通过使用信号量来实现进程的同步。
共享内存函数
1、shmget函数
功能:⽤来创建共享内存
原型:int shmget(key_t key, size_t size, int shmflg);
参数:
key:这个共享内存段名字
size:共享内存⼤⼩
shmflg:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode模式标志是⼀样的
返回值:成功返回⼀个⾮负整数,即该共享内存段的标识码;失败返回-1
注意:只有创建权限是0666的才可以用命令行”ipcs -m”查看,其他类型权限的共享内存区无法被这个命令所查看。
2、shmctl函数
功能:⽤于控制共享内存
原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
IPC_ STAT:把shmid_ ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值
IPC_ SET:在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值
IPC_RMID:删除共享内存段
buf:指向⼀个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1
3、shmat函数
功能:将共享内存段连接到进程地址空间
原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
shmid:共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_ RND和SHM_RDONLY
返回值:成功返回⼀个指针,指向共享内存第⼀个节;失败返回-1
4、shmdt函数
功能:将共享内存段与当前进程脱离
原型:int shmdt(const void *shmaddr);
参数:
shmaddr:由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段
共享内存特点
共享内存实现进程间通信
以下两个程序是一个进程间通信的例子。这两个程序分别在不同的进程中运行,使用了共享内存进行通信。client读入数据,存放在共享内存中。server则从共享内存中读取数据,显示到屏幕上。
common.c
#include "common.h"
#include
int ShmCommon(int size, int flags){
key_t key = ftok(PATHNAME, PROJ_ID);
if(key < 0){
perror("ftok error");
return -1;
}
int shmid = shmget(key, size, flags);
if(shmid < 0){
perror("shmget error");
return 1;
}
return shmid;
}
int ShmCreate(int size){
return ShmCommon(size, IPC_CREAT | IPC_EXCL | 0666);
}
int ShmOpen(){
return ShmCommon(0, IPC_CREAT);
}
int ShmDestroy(int shmid){
int ret = shmctl(shmid, IPC_RMID, NULL);
if(ret < 0){
perror("shmctl error");
return -1;
}
return 0;
}
////////////////////////////////////////////////////////
//以下是测试代码
///////////////////////////////////////////////////////
#if 0
void TestCreate(){
int shmid = ShmCreate(1024);
printf("shmid = %d\n", shmid);
}
void TestOpen(){
int shmid = ShmOpen();
printf("shmid = %d\n", shmid);
}
void TestDestroy(){
int shmid = ShmOpen();
int ret = ShmDestroy(shmid);
printf("ret expect 0, actual %d\n", ret);
}
int main(){
//TestCreate();
//TestOpen();
TestDestroy();
return 0;
}
#endif
client.c
#include
#include
#include "common.h"
int main(){
int shmid = ShmOpen();
if(shmid < 0){
perror("ShmOpen failed!");
return 1;
}
sleep(1);
//把物理内存关联(挂接,attach)到某个进程的虚拟地址空间之中
char* addr = shmat(shmid, NULL, 0);
sleep(2);
int i = 0;
while(i < 26){
addr[i] = 'A' + i;
i++;
addr[i] = 0;
sleep(1);
}
//将共享内存与当前进程脱离
shmdt(addr);
sleep(2);
return 0;
}
server.c
#include
#include
#include "common.h"
int main(){
int shmid = ShmCreate(1024);
if(shmid < 0){
perror("ShmCreate failed!");
return 1;
}
char* addr = shmat(shmid, NULL, 0);
sleep(2);
int i = 0;
while(i++ < 26){
printf("client# %s\n", addr);
sleep(1);
}
shmdt(addr);
sleep(2);
ShmDestroy(shmid);
return 0;
}
详细代码请参考Git