共享内存,顾名思义就是允许两个不相关地进程访问同一个逻辑内存。共享内存是在两个正在运行地进程之间共享和传递数据的一种非常有效的方式。
不同进程之间共享的内存通常安排在同一段物理内存中;进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址。
不过,共享内存并未提供同步机制,也就是说,在第一个进程对共享内存的写操作结束之前,并无自动机制可以阻止第二个进程对它进行读取。以通常需要用其他的机制来同步对共享内存的的访问
创建共享内存
(1)在 L i n u x Linux Linux下,可以通过 s h m g e t shmget shmget函数来创建共享内存,函数原型:
#include <sys/shm.h>
int shmget(key_t key, int size, int flag);
- 1)第一个参数 k e y key key,有效的为共享内存命名, s h m g e t shmget shmget函数运行成功会返回一个与 k e y key key相关的共享内存标识符,用于后续共享内存函数;失败则返回-1
- 2) s i z e size size以字节为单位指定需要共享的内存容量
- 3) s h m f l g shmflg shmflg是权限标志,作用与 o p e n open open函数的 m o d e mode mode参数一样,如果要想在 k e y key key标识的共享内存不存在的条件下创建它的话,可以与 I P C IPC IPC_ C R E A T CREAT CREAT做或操作
(2)当共享内存创建后,其余进程可以调用 s h m a t shmat shmat将其连接到自身的地址空间中,函数原型:
void *shmat(int shmid, void *addr, int flag);
- 1) s h m i d shmid shmid为 s h m g e t shmget shmget函数返回的共享存储标识符
- 2) a d d r addr addr和 f l a g flag flag参数决定了以什么方式来确定连接的地址,函数的返回值即是该进程数据段所连接的实际地址
(3) s h m d t shmdt shmdt函数用于将共享内存从当前进程中分离。函数原型:
int shmdt(const void *shmaddr);
- 参数 s h m a d d r shmaddr shmaddr是 s h m a t shmat shmat函数返回的地址指针,调用成功时返回0,失败时返回-1
例1:两个不相关的进程来说明进程间如何通过共享内存来进行通信(生产者-消费者模型)
//方便操作和数据结构的统一
/*************************************************************************
> File Name: shm_com.h
> Author: ersheng
> Mail: ershengaaa@163.com
> Created Time: Sat 02 Mar 2019 03:53:48 PM CST
************************************************************************/
#ifndef _SHMCOM_H_HEADER
#define _SHMCOM_H_HEADER
#define TEXT_SZ 2048
struct shared_use_st {
int written;
char text[TEXT_SZ];
};
#endif
//consumer.cpp
/*************************************************************************
> File Name: consumer.cpp
> Author: ersheng
> Mail: ershengaaa@163.com
> Created Time: Sat 02 Mar 2019 03:56:05 PM CST
************************************************************************/
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "shm_com.h"
using namespace std;
int main(){
int shmid;
srand((unsigned int)getpid());
//创建共享内存
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
if (shmid == -1) {
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
void *shared_memory = (void *)0;
//连接到自身的地址空间
shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X\n", (long)shared_memory);
struct shared_use_st *shared_stuff;
shared_stuff = (struct shared_use_st *)shared_memory;
shared_stuff->written = 0;
int running = 1;
while (running) {
if (shared_stuff->written) { //可读
printf("You wrote: %s", shared_stuff->text);
sleep(rand() % 4);
shared_stuff->written = 0;
if (strncmp(shared_stuff->text, "end", 3) == 0) {
running = 0;
}
}
}
if (shmdt(shared_memory) == -1) { //将共享内存分离
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
if (shmctl(shmid, IPC_RMID, 0) == -1) { //修改共享内存属性
fprintf(stderr, "shmctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
//producer.cpp
/*************************************************************************
> File Name: producer.cpp
> Author: ersheng
> Mail: ershengaaa@163.com
> Created Time: Sat 02 Mar 2019 04:08:37 PM CST
************************************************************************/
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "shm_com.h"
using namespace std;
#define BUFSIZE 2048
int main() {
int shmid;
//创建共享内存,key值与consumer中相同,为同一共享内存
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
if (shmid == -1) {
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
void *shared_memory = (void *)0;
//连接到自身的地址空间
shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X\n", (long)shared_memory);
struct shared_use_st *shared_stuff;
shared_stuff = (struct shared_use_st *)shared_memory;
int running = 1;
char buffer[BUFSIZE];
while (running) {
while (shared_stuff->written == 1) {
sleep(1);
printf("waiting for client...\n");
}
printf("Enter some text: ");
fgets(buffer, BUFSIZE, stdin);
strncpy(shared_stuff->text, buffer, TEXT_SZ);
shared_stuff->written = 1;
if (strncmp(shared_stuff->text, "end", 3) == 0) {
running = 0;
}
}
if (shmdt(shared_memory) == -1) {
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
使用共享内存的优缺点:
-(1)优点:使用共享内存进行进程间的通信非常方便,而且函数的接口也非常简单,数据的共享还使进程间的数据不同传送,而是直接访问内存,也加快了程序的效率。同时,它也不像无名管道那样要求通信的进程有一定的父子关系
- (2) 缺点:共享内存没有提供同步的机制,这使得在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作