共享内存作用:
让同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新
共享内存使用步骤:(这里还有要通过ftok()函数获得键值,所以还有打开文件的操作)
1.进程调用shmget函数创建新的或获取已有共享内存
2.进程调用shmat函数,将物理内存映射到自己的进程空间
3.shmdt函数,取消映射
4.调用shmctl函数释放开辟的那片物理内存空间
对应API:
int shmget(key_t key, size_t size, int shmflg);
key为通过ftok()函数生成的键值,size为共享内存大小,shmflg为权限,一般用0644 | IPC_CREAT
返回值:
成功:返回共享内存的标识符,以后续操作
失败:返回-1,并且errno被设置
void *shmat(int shmid, const void *shmaddr, int shmflg);
将物理内存映射到虚拟地址空间中
shmaddr为指定映射起始地址,但一般设为NULL,防止团队合作中该地址与其他人设置的地址冲突;shmflg为指定映射条件,有0(可读可写),SHM_RDONLY(只读)两种选项
返回值:
成功:返回映射地址;
失败:返回(void *)-1,并且errno被设置
int shmdt(const void *shmaddr);
取消建立的映射
返回值:
调用成功返回0,失败返回-1,且errno被设置
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:根据cmd的要求,对共享内存进行相应控制
比如:
获取共享内存的属性信息
修改共享内存的属性信息
删除共享内存
参数:
shmid:标识符。
cmd:控制选项
IPC_STAT:从内核获取共享内存属性信息到第三个参数(应用缓存)
IPC_SET:修改共享内存的属性
修改方法与消息队列相同
IPC_RMID:删除共享内存,不过前提是只有当所有的映射取消后,才能删除共享内存,删除时,用不着第三个参数,所以设置为NULL
下面举个栗子:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#define MAX_SIZE 1024
char *addr;
int shmid;
/*void my_exit(int signal)
{
shmdt(addr);
shmctl(shmid,IPC_RMID,NULL);
}*/
int main()
{
//signal(SIGINT,my_exit);
char buffer[MAX_SIZE];
if(open("./shm",O_CREAT | O_RDWR) < 0)
{
perror("open error!");
exit(1);
}
key_t key = ftok("./shm",'b');
shmid = shmget(key,MAX_SIZE,0644 | IPC_CREAT);
if(shmid == -1)
{
perror("shm get error!");
exit(1);
}
pid_t pid = fork();
if(pid < 0)
{
perror("fork error!");
exit(1);
}
if(pid == 0)
{
addr = (char *)shmat(shmid,NULL,0);
while(1)
{
memset(buffer,0,sizeof(buffer));
if(strlen(addr) != 0)
{
strcpy(buffer,addr);
printf("recv:%s\n",buffer);
memset(addr,0,MAX_SIZE);
}
sleep(2);
}
}
else if(pid > 0)
{
addr = (char *)shmat(shmid,NULL,0);
while(1)
{
memset(buffer,0,sizeof(buffer));
scanf("%s",buffer);
strcpy(addr,buffer);
}
}
return 0;
}
该程序功能很简单,就是父进程往共享内存中写内容,子进程从共享内存中读内容,但子进程加了个条件:每次读完输出结束后,清空共享内存,并且共享内存为无内容时就一直sleep,不占用资源,换句话说就是父进程不写入新内容子进程不输出;不这样做的话子进程会一直输出上一条消息。
结果如下: