共享内存是内核中开辟一块内存由IPC对象进行管理,进程A、B都用纸自己的虚拟地址与之映射,这样就达到了共享同一块内存。
特点:
优点:不需要复制信息,是最快的一种进程间通信机制。
缺点:需要考虑同步问题(必须借助其他机制,如信号)
***编程模型***
进程A 进程B
生成IPC键值 ftok 生成IPC键值 ftok
创建共享内存 shmget 获取共享内存 shmget
映射共享内存 shmat 映射共享内存 shmat
使用共享内存 *ptr 使用共享内存 *ptr
取消映射 shmdt 取消映射 shmdt
删除共享内存 shmctl ...
共享内存所使用的函数:
#include <sys/ipc.h>
#include <sys/shm.h>
Int shmget(key_t key, size_t size, int shmflg);
功能:创建或获取共享内存
key:IPC键值,由ftok函数生成
size:共享内存的大小,最好是4096的整数倍,(获取共享内存时,此值无效)
shmflg:
0 获取共享内存
IPC_CREAT 创建
IPC_EXCL 如果存在则创建失败
返回值:成功返回共享内存标识(IPC标识),失败返回-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享内存
shmid :共享内存标识符,shmget的返回值
shmaddr:进程提供的虚拟地址,与内核中的内存映射,也可以是NULL(内核自动选择一个地址映射)
shmflg:
0 自动分配
SHM_RDONLY 只读权限
SHM_RND 当shmaddr不为NULL时,shmaddr向下去整页
返回值:映射成功后的虚拟地址
Int shmdt(const void *shmaddr);
功能:取消虚拟地址与共享内存的映射
shmaddr:被映射过的虚拟地址
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:删除共享内存,获取/设置共享内存的属性
shmid:共享内存标识符shmget的返回值
cmd:
IPC_STAT 获取共享内存的属性
IPC_SET 设置共享内存的属性
IPC_RMID 删除共享内存 buf = NULL
buf:(获取/设置)
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; 创建者进程ID /* PID of creator */
pid_t shm_lpid; 最后映射/取消映射的进程ID/* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; 映射的次数 /* No. of current attaches */
...
};
struct ipc_perm
{
key_t __key; IPC键值 /* Key supplied to shmget(2) */
uid_t uid; 有效用户ID /* Effective UID of owner */
gid_t gid; 有效组ID /* Effective GID of owner */
uid_t cuid; 创建者的用户ID /* Effective UID of creator */
gid_t cgid; 创建者的组ID /* Effective GID of creator */
unsigned short mode; 权限 /* Permissions + SHM_DEST and SHM_LOCKED flags */
unsigned short __seq; IPC标识 /* Sequence number */
};
共享内存进程A实现代码:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/shm.h>
#include<signal.h>
int main()
{
//1.创建IPC键值
key_t key = ftok(".",8888);
//2. 创建共享内存
int shmid = shmget(key,4096,IPC_CREAT|IPC_EXCL|0644);
if(0 > shmid)
{
perror("shmget");
return -1;
}
//3.映射
char* str = shmat(shmid,NULL,SHM_RND);
if(NULL == str)
{
perror("shmat");
return -1;
}
//4.使用
pid_t pid = 0;
printf("请输入要通信的进程号:");
scanf("%u",&pid);
stdin->_IO_read_ptr = stdin->_IO_read_end;
while(1)
{
printf(">");
gets(str);
kill(pid,SIGINT);
if(0 == strcmp(str,"quit"))
{
printf("通信结束\n");
break;
}
}
//5.取消映射
if(0 > shmdt(str))
{
perror("shmdt");
return -1;
}
//6.删除共享内存
if(0 > shmctl(shmid,IPC_RMID,NULL))
{
perror("shmctl");
return -1;
}
return 0;
}
共享内存进程B实现代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/shm.h>
#include<signal.h>
int main()
{
printf("进程id:%u\n",getpid());
//1. 创建IPC键值
key_t key = ftok(".",8888);
//2.获取共享内存
int shmid = shmget(key,0,0);
if(0 > shmid)
{
perror("shmget");
return -1;
}
//3.映射
char* str = shmat(shmid,NULL,SHM_RND);
if(NULL == str)
{
perror("shamt");
return -1;
}
//4.使用
void sigint(int sig)
{
printf("read:%s\n",str);
if(0 == strcmp(str,"quit"))
{
printf("通信结束\n");
if(0 > shmdt(str))
{
perror("shmdt");
}
exit(0);
}
}
signal(SIGINT,sigint);
while(1);
pause();
return 0;
}
171

被折叠的 条评论
为什么被折叠?



