共享内存

我们学会了争抢,学会了占有,学会了排斥,却唯独没有学会分享

共享内存是linux中最为重要的IPC及硬件组件通信方式之一,本文将针对共享内存基本使用方法、常见共享内存模型以及共享内存并发访问保护等方面进行总结。

共享内存使用

linux下实现共享内存的方式有很多,本节将基于SYS V创建共享内存实现IPC通信,并总结一些常见的模型

基本使用方法(SYS V)

SYS V的共享内存即对应内核代码linux/ipc/shm.c,使用方式比较奇怪,以文件作为中介,使用attach和detach的方式进行映射和解映射,我在这里封装了一套接口用于创建和销毁共享内存,其中创建的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void *AttachShm(const char *fileName)
{
key_t key;
int shmid;
char *buf = NULL;

/* Generate a key for shared memory based on an existing file */
key = ftok(fileName, 'R');
if (key < 0) {
printf("Attach file failed!\n");
return (void *)-1;
}

/* Create shared memory for the sensor */
shmid = shmget(key, maxShmSize, 0644 | IPC_CREAT);
if (shmid < 0) {
printf("Get shared memory failed!\n");
return (void *)-1;
}

buf = shmat(shmid, NULL, 0);
if (buf == NULL) {
printf("Attach shared memory failed!\n");
return (void *)-1;
}

return buf;
}

销毁的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int DetachShm(char *buf)
{
int ret;

if (buf == NULL) {
printf("No need to free buf!\n");
return -1;
}

ret = shmdt(buf);
if (ret != 0) {
printf("Failed to detach memory!\n");
return -1;
}

return 0;
}

基本模型1:不带保护的生产者/消费者问题

在创建共享内存后,我们就可以进行进程间通信,一个基本的读写者模型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* Create and init a sensor */    
char *buf = NULL;
buf = AttachShm("./shm.txt");

/* Write the buf */
for (int i = 0; i < 10; i++) {
ShmWrite(buf, argv[1]);
}

ret = DetachShm(buf);

/* A reader continue reading the buf */
bool done = false;
buf = AttachShm("shm.txt");

while (1) {
if (strlen(buf) > 0) {
printf("Reading: %s\n", buf);
done = (strcmp(buf, "quit") == 0);
buf[0] = '\0'; /* Clear the buf when read finished */
if (done) {
break;
}
}
}

ret = DetachShm(buf);

当然,上面这个读写模型没有并发保护,存在并发问题,运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
duan@ubuntu:~/Code/OS/memory/cmake/src$ ./server 123
In ShmWrite: buf is 123
In ShmWrite: buf is 123
In ShmWrite: buf is 123
In ShmWrite: buf is 123
In ShmWrite: buf is 123
In ShmWrite: buf is 123
In ShmWrite: buf is 123
In ShmWrite: buf is 123
In ShmWrite: buf is 123
In ShmWrite: buf is 123

duan@ubuntu:~/Code/OS/memory/cmake/src$ ./client
Reading: 123

两个终端,写者写了10次,但是读者只读了一次,读者在读的时候没有阻止写操作,读取到的次数是随机的,无法使用。

基本模型2:由单个信号量进行读写保护的生产者/消费者问题

现在我们使用信号量对共享内存的访问进行并发保护,我们创建两个信号量,分别用于生产者和消费者,基本逻辑如下:

  • 当生产者开始生产时,需要wait(reader),当生产完毕后,需要post(writer)
  • 当消费者开始消费时,需要wait(writer),当消费完毕后,需要post(reader)
1
2
#define SEM_WRITER_FNAME "/writer"
#define SEM_READER_FNMAE "/reader"

参考文献

0%