共享内存,顾名思义就是多个进程共用同一块物理内存;这块物理内存被映射到不同进程的地址空间中进行通信,A进程可以及时看到B进程对共享内存中数据的更新,反之亦然。
不同的进程可以直接读写内存,所以它最大的特点就是效率高,但是共享内存本身不带任何同步互斥机制,所以当多个进程同时对共享内存操作时会破坏内容,所以,我们使用共享内存通信时候,同步互斥机制要我们用户自己来完成。
共享内存特点:
1. 没有同步互斥机制
2. 全双工
3. 用于任意进程
4. 生命周期随内核
相关函数:
1.
//创建共享内存
int shmget(key_t key,size_t size,int shmflg);
参数:
key:共享内存段名字;
size:共享内存的大小,(注意:这里的大小是一页的大小,1页=4k,所以这里的大小是1024的整数倍);
shmflg:由9个权限标志位组成,用法与消息队列相同;
2
//挂接共享内存与当前进程
void* shmat(int shmid,const void* shmaddr,int shmflg);
//取消共享内存与当前进程的挂接
int shmdt(const void* shmddr);
参数:
shmid:共享内存标识;
shmddr:指定连接的地址;
shmflg:两个可能取值是SHM_RND和SHM_RDONLY(只读共享内存);
返回值:返回一个指针,指向共享内存的第一个节,失败返回-1;
4
//控制共享内存
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
参数:
shmid:共享内存标识;
cmd:要采取的三个动作(三个值可选,IPC_STAT,IPC_RMID,IPC_SET);
buf::指向⼀个保存着共享内存的模式状态和访问权限的数据结构(可设置为NULL);
返回值:成功返回0,失败返回1;
例子:client和server使用共享内存通信代码
//server.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define PATH_NAME "/tmp"
#define PATH_ID 0X6666
int main()
{
key_t k = ftok(PATH_NAME,PATH_ID); //创建标识符
if(k < 0)
{
printf("ftok error!\n");
return -1;
}
int shmid = shmget(k,4*1024,IPC_CREAT|IPC_EXCL|0x666); //开辟共享内存
if(shmid < 0)
{
printf("shmget error!\n");
}
char* ptr = (char*)shmat(shmid,NULL,0); //挂接共享内存
while(1)
{
printf("%s\r",ptr);
fflush(stdout);
sleep(1);
}
shmdt(ptr); //取消挂接共享内存
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
//client.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define PATH_NAME "/tmp"
#define PATH_ID 0X6666
int main()
{
key_t k = ftok(PATH_NAME,PATH_ID); //创建标识符
if(k < 0)
{
printf("ftok error!\n");
return -1;
}
int shmid = shmget(k,4*1024,IPC_CREAT); //开辟共享内存
if(shmid < 0)
{
printf("shmget error!\n");
}
char* ptr = (char*)shmat(shmid,NULL,0); //挂接共享内存
int x = 'A';
for(;x<='Z';++x)
{
ptr[x-'A'] = x;
ptr[x-'A'+1] = '\0';
sleep(1);
}
shmdt(ptr); //取消挂接共享内存
return 0;
}
查看一下系统共享内存资源:
注意:shmdt()是取消挂接,并不是删除共享内存;
删除共享内存可以调用shmctl()函数,也可以使用命令:ipcrm -m 标识符
运行结果: