在学校的时候, 谁会搞共享内存这些东西呢? 不过是为了笔试和面试, 大家才搞一下吧。 但是, 在实际工作中, 共享内存确实应用较广。
其实, 共享内存的思想很简单, 我来举个俗气的例子, writer进程和和reader进程通信, 最简单的方式是什么: 当然是共享文件啊。 writer进程把数据写到a.txt文件, 然后reader进程从a.txt文件中读取数据, 这就实现了进程间的通信。 我当时读书的时候, 就是这么干的。 在学校阶段, 确实解决了当时的问题, 靠谱。 但在公司, 谁敢这么搞?
共享内存也是采用了类似的思路, 只不过, 共享的不是文件, 而是内存。 就是如此简单。
话不多说, 来看点代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 1#include <stdio.h>
2#include <string.h>
3#include <unistd.h>
4#include <stdlib.h>
5#include <sys/shm.h>
6
7int main()
8{
9 int shmid = shmget((key_t)1234, 100, 0666|IPC_CREAT);
10 printf("shmid %d\n", shmid);
11
12 return 0;
13}
14
1
2 1 key是1234, 对应的16进制是0x000004d2, 100是设定的共享内存大小。 我们看看结果:
2
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 1xxxxxx:~/network> ipcs
2
3------ Shared Memory Segments --------
4key shmid owner perms bytes nattch status
50x115fd81a 32768 root 666 4096 2
60x294b8556 65537 root 666 13497727 1
7
8------ Semaphore Arrays --------
9key semid owner perms nsems
100x0000870a 0 root 666 1
110x00008707 32769 root 666 1
120x00008709 65538 root 666 1
130x0000870b 98307 root 666 1
14
15------ Message Queues --------
16key msqid owner perms used-bytes messages
17
18xxxxxx:~/network>
19xxxxxx:~/network>
20xxxxxx:~/network>
21xxxxxx:~/network> ./test
22shmid 294915
23xxxxxx:~/network> ipcm
24-bash: ipcm: command not found
25xxxxxx:~/network> ipcs
26
27------ Shared Memory Segments --------
28key shmid owner perms bytes nattch status
290x115fd81a 32768 root 666 4096 2
300x294b8556 65537 root 666 13497727 1
310x000004d2 294915 xxxxxx 666 100 0
32
33------ Semaphore Arrays --------
34key semid owner perms nsems
350x0000870a 0 root 666 1
360x00008707 32769 root 666 1
370x00008709 65538 root 666 1
380x0000870b 98307 root 666 1
39
40------ Message Queues --------
41key msqid owner perms used-bytes messages
42
43xxxxxx:~/network>
44
1
2 1 可以看到, 运行程序前, 没有用户xxxxxx对应的共享内存, 运行后, 创建了一块共享内存, 其信息和我们在程序中设置的信息完全一致。
2
这里要注意一下几点(有兴趣的同学可以多多尝试)
1. 调用shmget的时候, 如果共享内存key已经存在, 则不是创建一块新共享内存, 而是返回已经存在的共享内存。
2. 进程退出后, 共享内存不会释放, 需要调用shmctr函数, 或者用ipcrm命令才可释放。
3. ipcs和ipcrm要用熟。
有点迫不及待看共享内存的实际代码了, 一起来看看:
writer.cpp
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
29
30
31
32
33
34
35
36 1#include <stdio.h>
2#include <string.h>
3#include <unistd.h>
4#include <stdlib.h>
5#include <sys/shm.h>
6#define TEST_SIZE 2048
7
8typedef struct _BOX
9{
10 int flag;
11 char szMsg[TEST_SIZE];
12}Box;
13
14int main()
15{
16 int shmid = shmget((key_t)1234, sizeof(Box), 0666|IPC_CREAT);
17 void *shm = shmat(shmid, (void*)0, 0);
18 Box *pBox = (Box*)shm;
19 pBox->flag = 0;
20
21 int i = 0;
22 while(1)
23 {
24 while(pBox->flag == 0)
25 {
26 getchar();
27 snprintf(pBox->szMsg, sizeof(pBox->szMsg), "hello %d", ++i);
28 printf("write msg is [%s]\n", pBox->szMsg);
29 pBox->flag = 1;
30 }
31 }
32
33 shmdt(shm);
34 return 0;
35}
36
1
2 1 reader.cpp的内容为:
2
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
29
30
31
32
33 1#include <stdio.h>
2#include <string.h>
3#include <unistd.h>
4#include <stdlib.h>
5#include <sys/shm.h>
6#define TEST_SIZE 2048
7
8typedef struct _BOX
9{
10 int flag;
11 char szMsg[TEST_SIZE];
12}Box;
13
14int main()
15{
16 int shmid = shmget((key_t)1234, sizeof(Box), 0666|IPC_CREAT);
17 void *shm = shmat(shmid, 0, 0);
18 Box *pBox = (Box*)shm;
19
20 while(1)
21 {
22 if(pBox->flag == 1)
23 {
24 printf("msg from writer is [%s]\n", pBox->szMsg);
25 pBox->flag = 0;
26 }
27 }
28
29 shmdt(shm);
30 shmctl(shmid, IPC_RMID, 0);
31 return 0;
32}
33
先启动writer, 再启动reader, 于是乎, writer逐渐往共享内存中写数据(按enter键), reader不断读共享内存的数据, 结果为(如下只给出reader端的结果):
1
2
3
4
5
6
7
8
9
10
11 1msg from writer is [hello 1]
2msg from writer is [hello 2]
3msg from writer is [hello 3]
4msg from writer is [hello 4]
5msg from writer is [hello 5]
6msg from writer is [hello 6]
7msg from writer is [hello 7]
8msg from writer is [hello 8]
9msg from writer is [hello 9]
10msg from writer is [hello 10]
11
1
2 1 可见, 在writer端不断按enter键盘的时候, 消息源源不断地“流向”了reader, 就是如此简单。 至于代码中的函数, 直接man一下, 一切就一目了然了。
2
共享内存是最快的进程间通信方式, 没有之一。 但同步的问题, 还得应用程序自己解决。
OK, 不多说。