【共享内存概述】
共享内存时一种最为高效的进程间通信方式,进程可以直接读写内存,不需要任何数据的复制。为了在多个进程之间交换信息,内核专门留出了一块内存区,这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。因此,进程就可以直接读写这一内存区而不需要进行数据复制,从而大大提高了效率。但共享内存本身并不具备同步机制,所以当多个进程共享一段内存时,就需要借助互斥锁、信号量等实现同步。
【共享内存编程】
【编程步骤】
一、创建共享内存,用到的函数是shmget(),也就是从内存中获得一段共享内存区域;
二、映射共享内存,也就是把这段创建的共享内存映射到具体的进程空间中,使用到的函数是shmat()。至此就可以使用这段共享内存了,即使用不带缓冲的I/O读写命令对其进行操作。
三、撤销映射,其函数为shmdt()。
【函数说明】
1、shmget()函数
头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型:
int shmget(key_t key, int size, int shmflg)
传入值:
key:共享内存的键值,多个进程可以通过它访问同一个共享内存,其中有个特殊值IPC_PRIVATE。它用于创建当前进程的私有共享内存。
size:共享内存区大小
shmflg:同open()函数权限位,也可以用八进制表示法
返回值:
成功返回共享内存段标识符
失败返回-1
2、shmat()函数
头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型:
char *shmat(int shmid, const void *shmaddr, int shmflg)
传入值:
shmid:要映射的共享内存区标识符
shmaddr:将共享内存映射到指定地址(若为0则表示系统自动分配地址并把该段共享内存映射到调用进程的地址空间)
shmflg:默认0,共享内存可读写
SHM_RDONLY,共享内存只读
返回值:
成功返回被映射的地址段
失败返回-1
3、shmdt()函数
头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型:
int shmdt(const void *shmaddr)
传入值:
shmaddr:被映射的共享内存段地址
返回值:
成功返回0
失败返回-1
【代码示例】
【头文件】
#ifndef __SHM_H__
#define __SHM_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <pthread.h>
typedef struct st_shm
{
sem_t sem1;
sem_t sem2;
int data;
}sh;
#endif
【程序1:生产】
/*******
*共享内存
*******/
#include "shm.h"
int main()
{
int shmid = -1;
sh *pshm = NULL;
int ret;
//创建共享内存
shmid = shmget((key_t)0x01020304, sizeof(sh), IPC_CREAT|0666);
if (shmid < 0)
{
perror("shmget");
exit(1);
}
//加载共享内存
pshm = (sh *)shmat(shmid, NULL, 0);
if (pshm == (void *)-1)
{
perror("shmat");
exit(1);
}
//信号量初始化
ret = sem_init(&(pshm->sem1), 1, 1);
if (ret < 0)
{
perror("sem_init");
exit(1);
}
ret = sem_init(&(pshm->sem2), 1, 0);
if (ret < 0)
{
perror("sem_init");
exit(1);
}
pshm->data = 0;
while (1)
{
sem_wait(&pshm->sem1);
pshm->data++;
printf("生产【%d】\n", pshm->data);
sleep(1);
sem_post(&pshm->sem2);
}
}
【程序2:消费】
/*******
*共享内存
*******/
#include "shm.h"
int main()
{
int shmid = -1;
sh *pshm = NULL;
int ret;
//获得共享内存
shmid = shmget((key_t)0x01020304, sizeof(sh), 0);
if (shmid < 0)
{
perror("shmget");
exit(1);
}
//映射共享内存
pshm = (sh *)shmat(shmid, NULL, 0);
if (pshm == (void *)-1)
{
perror("shmat");
exit(1);
}
while (1)
{
sem_wait(&pshm->sem2);
printf("消费【%d】\n", pshm->data);
sem_post(&pshm->sem1);
}
}