详解Linux进程间通信——使用共享内存
<p><span><strong>一、什么是共享内存</strong></span></p>
<p>
顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。</p>
<p>
<strong>特别提醒:</strong>共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问,例如前面说到的信号量。有关信号量的更多内容,可以查阅我的另一篇文章:Linux进程间通信——使用信号量</p>
<p>
<span><strong>二、共享内存的使得</strong></span></p>
<p>
与信号量一样,在Linux中也提供了一组函数接口用于使用共享内存,而且使用共享共存的接口还与信号量的非常相似,而且比使用信号量的接口来得简单。它们声明在头文件 sys/shm.h中。</p>
<p>
<strong>1、shmget函数</strong></p>
<p>
该函数用来创建共享内存,它的原型为:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightercpp" id="highlighter_798885">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="cpp color1 bold">int</code> <code class="cpp plain">shmget(key_t key, </code><code class="cpp color1 bold">size_t</code> <code class="cpp plain">size, </code><code class="cpp color1 bold">int</code> <code class="cpp plain">shmflg);</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
第一个参数,与信号量的semget函数一样,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,shmget函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函数。调用失败返回-1.</p>
<p>
不相关的进程可以通过该函数的返回值访问同一共享内存,它代表程序可能要使用的某个资源,程序对所有共享内存的访问都是间接的,程序先通过调用shmget函数并提供一个键,再由系统生成一个相应的共享内存标识符(shmget函数的返回值),只有shmget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。</p>
<p>
第二个参数,size以字节为单位指定需要共享的内存容量</p>
<p>
第三个参数,shmflg是权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。</p>
<p>
<strong>2、shmat函数</strong></p>
<p>
第一次创建完共享内存时,它还不能被任何进程访问,shmat函数的作用就是用来启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。它的原型如下:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightercpp" id="highlighter_43157">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="cpp keyword bold">void</code> <code class="cpp plain">*shmat(</code><code class="cpp color1 bold">int</code> <code class="cpp plain">shm_id, </code><code class="cpp keyword bold">const</code> <code class="cpp keyword bold">void</code> <code class="cpp plain">*shm_addr, </code><code class="cpp color1 bold">int</code> <code class="cpp plain">shmflg); </code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
第一个参数,shm_id是由shmget函数返回的共享内存标识。</p>
<p>
第二个参数,shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。</p>
<p>
第三个参数,shm_flg是一组标志位,通常为0。</p>
<p>
调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1.</p>
<p>
<strong>3、shmdt函数</strong></p>
<p>
该函数用于将共享内存从当前进程中分离。注意,将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用。它的原型如下:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightercpp" id="highlighter_61024">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="cpp color1 bold">int</code> <code class="cpp plain">shmdt(</code><code class="cpp keyword bold">const</code> <code class="cpp keyword bold">void</code> <code class="cpp plain">*shmaddr);</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
参数shmaddr是shmat函数返回的地址指针,调用成功时返回0,失败时返回-1.</p>
<p>
<strong>4、shmctl函数</strong></p>
<p>
与信号量的semctl函数一样,用来控制共享内存,它的原型如下:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightercpp" id="highlighter_366165">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="cpp color1 bold">int</code> <code class="cpp plain">shmctl(</code><code class="cpp color1 bold">int</code> <code class="cpp plain">shm_id, </code><code class="cpp color1 bold">int</code> <code class="cpp plain">command, </code><code class="cpp keyword bold">struct</code> <code class="cpp plain">shmid_ds *buf);</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
第一个参数,shm_id是shmget函数返回的共享内存标识符。</p>
<p>
第二个参数,command是要采取的操作,它可以取下面的三个值 :</p>
<ul>
<li>
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。</li>
<li>
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值</li>
<li>
IPC_RMID:删除共享内存段</li>
</ul>
<p>
第三个参数,buf是一个结构指针,它指向共享内存模式和访问权限的结构。</p>
<p>
shmid_ds结构至少包括以下成员:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightercpp" id="highlighter_932063">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
<div class="line number6 index5 alt1">
6</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="cpp keyword bold">struct</code> <code class="cpp plain">shmid_ds </code>
</div>
<div class="line number2 index1 alt1">
<code class="cpp plain">{ </code>
</div>
<div class="line number3 index2 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">uid_t shm_perm.uid; </code>
</div>
<div class="line number4 index3 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">uid_t shm_perm.gid; </code>
</div>
<div class="line number5 index4 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">mode_t shm_perm.mode; </code>
</div>
<div class="line number6 index5 alt1">
<code class="cpp plain">};</code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
<span><strong>三、使用共享内存进行进程间通信</strong></span></p>
<p>
说了这么多,又到了实战的时候了。下面就以两个不相关的进程来说明进程间如何通过共享内存来进行通信。其中一个文件shmread.c创建共享内存,并读取其中的信息,另一个文件shmwrite.c向共享内存中写入数据。为了方便操作和数据结构的统一,为这两个文件定义了相同的数据结构,定义在文件shmdata.c中。结构shared_use_st中的written作为一个可读或可写的标志,非0:表示可读,0表示可写,text则是内存中的文件。</p>
<p>
shmdata.h的源代码如下:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightercpp" id="highlighter_752912">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
<div class="line number6 index5 alt1">
6</div>
<div class="line number7 index6 alt2">
7</div>
<div class="line number8 index7 alt1">
8</div>
<div class="line number9 index8 alt2">
9</div>
<div class="line number10 index9 alt1">
10</div>
<div class="line number11 index10 alt2">
11</div>
<div class="line number12 index11 alt1">
12</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="cpp preprocessor">#ifndef _SHMDATA_H_HEADER </code>
</div>
<div class="line number2 index1 alt1">
<code class="cpp preprocessor">#define _SHMDATA_H_HEADER </code>
</div>
<div class="line number3 index2 alt2">
<code class="cpp spaces"> </code>
</div>
<div class="line number4 index3 alt1">
<code class="cpp preprocessor">#define TEXT_SZ 2048 </code>
</div>
<div class="line number5 index4 alt2">
<code class="cpp spaces"> </code>
</div>
<div class="line number6 index5 alt1">
<code class="cpp keyword bold">struct</code> <code class="cpp plain">shared_use_st </code>
</div>
<div class="line number7 index6 alt2">
<code class="cpp plain">{ </code>
</div>
<div class="line number8 index7 alt1">
<code class="cpp spaces"> </code><code class="cpp color1 bold">int</code> <code class="cpp plain">written;</code><code class="cpp comments">//作为一个标志,非0:表示可读,0表示可写 </code>
</div>
<div class="line number9 index8 alt2">
<code class="cpp spaces"> </code><code class="cpp color1 bold">char</code> <code class="cpp plain">text;</code><code class="cpp comments">//记录写入和读取的文本 </code>
</div>
<div class="line number10 index9 alt1">
<code class="cpp plain">}; </code>
</div>
<div class="line number11 index10 alt2">
<code class="cpp spaces"> </code>
</div>
<div class="line number12 index11 alt1">
<code class="cpp preprocessor">#endif </code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
源文件shmread.c的源代码如下:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightercpp" id="highlighter_234541">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
<div class="line number6 index5 alt1">
6</div>
<div class="line number7 index6 alt2">
7</div>
<div class="line number8 index7 alt1">
8</div>
<div class="line number9 index8 alt2">
9</div>
<div class="line number10 index9 alt1">
10</div>
<div class="line number11 index10 alt2">
11</div>
<div class="line number12 index11 alt1">
12</div>
<div class="line number13 index12 alt2">
13</div>
<div class="line number14 index13 alt1">
14</div>
<div class="line number15 index14 alt2">
15</div>
<div class="line number16 index15 alt1">
16</div>
<div class="line number17 index16 alt2">
17</div>
<div class="line number18 index17 alt1">
18</div>
<div class="line number19 index18 alt2">
19</div>
<div class="line number20 index19 alt1">
20</div>
<div class="line number21 index20 alt2">
21</div>
<div class="line number22 index21 alt1">
22</div>
<div class="line number23 index22 alt2">
23</div>
<div class="line number24 index23 alt1">
24</div>
<div class="line number25 index24 alt2">
25</div>
<div class="line number26 index25 alt1">
26</div>
<div class="line number27 index26 alt2">
27</div>
<div class="line number28 index27 alt1">
28</div>
<div class="line number29 index28 alt2">
29</div>
<div class="line number30 index29 alt1">
30</div>
<div class="line number31 index30 alt2">
31</div>
<div class="line number32 index31 alt1">
32</div>
<div class="line number33 index32 alt2">
33</div>
<div class="line number34 index33 alt1">
34</div>
<div class="line number35 index34 alt2">
35</div>
<div class="line number36 index35 alt1">
36</div>
<div class="line number37 index36 alt2">
37</div>
<div class="line number38 index37 alt1">
38</div>
<div class="line number39 index38 alt2">
39</div>
<div class="line number40 index39 alt1">
40</div>
<div class="line number41 index40 alt2">
41</div>
<div class="line number42 index41 alt1">
42</div>
<div class="line number43 index42 alt2">
43</div>
<div class="line number44 index43 alt1">
44</div>
<div class="line number45 index44 alt2">
45</div>
<div class="line number46 index45 alt1">
46</div>
<div class="line number47 index46 alt2">
47</div>
<div class="line number48 index47 alt1">
48</div>
<div class="line number49 index48 alt2">
49</div>
<div class="line number50 index49 alt1">
50</div>
<div class="line number51 index50 alt2">
51</div>
<div class="line number52 index51 alt1">
52</div>
<div class="line number53 index52 alt2">
53</div>
<div class="line number54 index53 alt1">
54</div>
<div class="line number55 index54 alt2">
55</div>
<div class="line number56 index55 alt1">
56</div>
<div class="line number57 index56 alt2">
57</div>
<div class="line number58 index57 alt1">
58</div>
<div class="line number59 index58 alt2">
59</div>
<div class="line number60 index59 alt1">
60</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="cpp preprocessor">#include <unistd.h> </code>
</div>
<div class="line number2 index1 alt1">
<code class="cpp preprocessor">#include <stdlib.h> </code>
</div>
<div class="line number3 index2 alt2">
<code class="cpp preprocessor">#include <stdio.h> </code>
</div>
<div class="line number4 index3 alt1">
<code class="cpp preprocessor">#include <sys/shm.h> </code>
</div>
<div class="line number5 index4 alt2">
<code class="cpp preprocessor">#include "shmdata.h" </code>
</div>
<div class="line number6 index5 alt1">
<code class="cpp spaces"> </code>
</div>
<div class="line number7 index6 alt2">
<code class="cpp color1 bold">int</code> <code class="cpp plain">main() </code>
</div>
<div class="line number8 index7 alt1">
<code class="cpp plain">{ </code>
</div>
<div class="line number9 index8 alt2">
<code class="cpp spaces"> </code><code class="cpp color1 bold">int</code> <code class="cpp plain">running = 1;</code><code class="cpp comments">//程序是否继续运行的标志 </code>
</div>
<div class="line number10 index9 alt1">
<code class="cpp spaces"> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">*shm = NULL;</code><code class="cpp comments">//分配的共享内存的原始首地址 </code>
</div>
<div class="line number11 index10 alt2">
<code class="cpp spaces"> </code><code class="cpp keyword bold">struct</code> <code class="cpp plain">shared_use_st *shared;</code><code class="cpp comments">//指向shm </code>
</div>
<div class="line number12 index11 alt1">
<code class="cpp spaces"> </code><code class="cpp color1 bold">int</code> <code class="cpp plain">shmid;</code><code class="cpp comments">//共享内存标识符 </code>
</div>
<div class="line number13 index12 alt2">
<code class="cpp spaces"> </code><code class="cpp comments">//创建共享内存 </code>
</div>
<div class="line number14 index13 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">shmid = shmget((key_t)1234, </code><code class="cpp keyword bold">sizeof</code><code class="cpp plain">(</code><code class="cpp keyword bold">struct</code> <code class="cpp plain">shared_use_st), 0666|IPC_CREAT); </code>
</div>
<div class="line number15 index14 alt2">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(shmid == -1) </code>
</div>
<div class="line number16 index15 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number17 index16 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">fprintf</code><code class="cpp plain">(stderr, </code><code class="cpp string">"shmget failed\n"</code><code class="cpp plain">); </code>
</div>
<div class="line number18 index17 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">exit</code><code class="cpp plain">(EXIT_FAILURE); </code>
</div>
<div class="line number19 index18 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number20 index19 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//将共享内存连接到当前进程的地址空间 </code>
</div>
<div class="line number21 index20 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">shm = shmat(shmid, 0, 0); </code>
</div>
<div class="line number22 index21 alt1">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(shm == (</code><code class="cpp keyword bold">void</code><code class="cpp plain">*)-1) </code>
</div>
<div class="line number23 index22 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number24 index23 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">fprintf</code><code class="cpp plain">(stderr, </code><code class="cpp string">"shmat failed\n"</code><code class="cpp plain">); </code>
</div>
<div class="line number25 index24 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">exit</code><code class="cpp plain">(EXIT_FAILURE); </code>
</div>
<div class="line number26 index25 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number27 index26 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"\nMemory attached at %X\n"</code><code class="cpp plain">, (</code><code class="cpp color1 bold">int</code><code class="cpp plain">)shm); </code>
</div>
<div class="line number28 index27 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//设置共享内存 </code>
</div>
<div class="line number29 index28 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">shared = (</code><code class="cpp keyword bold">struct</code> <code class="cpp plain">shared_use_st*)shm; </code>
</div>
<div class="line number30 index29 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">shared->written = 0; </code>
</div>
<div class="line number31 index30 alt2">
<code class="cpp spaces"> </code><code class="cpp keyword bold">while</code><code class="cpp plain">(running)</code><code class="cpp comments">//读取共享内存中的数据 </code>
</div>
<div class="line number32 index31 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number33 index32 alt2">
<code class="cpp spaces"> </code><code class="cpp comments">//没有进程向共享内存定数据有数据可读取 </code>
</div>
<div class="line number34 index33 alt1">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(shared->written != 0) </code>
</div>
<div class="line number35 index34 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number36 index35 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"You wrote: %s"</code><code class="cpp plain">, shared->text); </code>
</div>
<div class="line number37 index36 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">sleep(</code><code class="cpp functions bold">rand</code><code class="cpp plain">() % 3); </code>
</div>
<div class="line number38 index37 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//读取完数据,设置written使共享内存段可写 </code>
</div>
<div class="line number39 index38 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">shared->written = 0; </code>
</div>
<div class="line number40 index39 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//输入了end,退出循环(程序) </code>
</div>
<div class="line number41 index40 alt2">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(</code><code class="cpp functions bold">strncmp</code><code class="cpp plain">(shared->text, </code><code class="cpp string">"end"</code><code class="cpp plain">, 3) == 0) </code>
</div>
<div class="line number42 index41 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">running = 0; </code>
</div>
<div class="line number43 index42 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number44 index43 alt1">
<code class="cpp spaces"> </code><code class="cpp keyword bold">else</code><code class="cpp comments">//有其他进程在写数据,不能读取数据 </code>
</div>
<div class="line number45 index44 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">sleep(1); </code>
</div>
<div class="line number46 index45 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number47 index46 alt2">
<code class="cpp spaces"> </code><code class="cpp comments">//把共享内存从当前进程中分离 </code>
</div>
<div class="line number48 index47 alt1">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(shmdt(shm) == -1) </code>
</div>
<div class="line number49 index48 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number50 index49 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">fprintf</code><code class="cpp plain">(stderr, </code><code class="cpp string">"shmdt failed\n"</code><code class="cpp plain">); </code>
</div>
<div class="line number51 index50 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">exit</code><code class="cpp plain">(EXIT_FAILURE); </code>
</div>
<div class="line number52 index51 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number53 index52 alt2">
<code class="cpp spaces"> </code><code class="cpp comments">//删除共享内存 </code>
</div>
<div class="line number54 index53 alt1">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(shmctl(shmid, IPC_RMID, 0) == -1) </code>
</div>
<div class="line number55 index54 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number56 index55 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">fprintf</code><code class="cpp plain">(stderr, </code><code class="cpp string">"shmctl(IPC_RMID) failed\n"</code><code class="cpp plain">); </code>
</div>
<div class="line number57 index56 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">exit</code><code class="cpp plain">(EXIT_FAILURE); </code>
</div>
<div class="line number58 index57 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number59 index58 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">exit</code><code class="cpp plain">(EXIT_SUCCESS); </code>
</div>
<div class="line number60 index59 alt1">
<code class="cpp plain">} </code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
源文件shmwrite.c的源代码如下:</p>
<div class="jb51code">
<div>
<div class="syntaxhighlightercpp" id="highlighter_709411">
<div class="toolbar">
<span>?</span>
</div>
<table border="0" cellpadding="0" cellspacing="0"><tbody><tr>
<td class="gutter">
<div class="line number1 index0 alt2">
1</div>
<div class="line number2 index1 alt1">
2</div>
<div class="line number3 index2 alt2">
3</div>
<div class="line number4 index3 alt1">
4</div>
<div class="line number5 index4 alt2">
5</div>
<div class="line number6 index5 alt1">
6</div>
<div class="line number7 index6 alt2">
7</div>
<div class="line number8 index7 alt1">
8</div>
<div class="line number9 index8 alt2">
9</div>
<div class="line number10 index9 alt1">
10</div>
<div class="line number11 index10 alt2">
11</div>
<div class="line number12 index11 alt1">
12</div>
<div class="line number13 index12 alt2">
13</div>
<div class="line number14 index13 alt1">
14</div>
<div class="line number15 index14 alt2">
15</div>
<div class="line number16 index15 alt1">
16</div>
<div class="line number17 index16 alt2">
17</div>
<div class="line number18 index17 alt1">
18</div>
<div class="line number19 index18 alt2">
19</div>
<div class="line number20 index19 alt1">
20</div>
<div class="line number21 index20 alt2">
21</div>
<div class="line number22 index21 alt1">
22</div>
<div class="line number23 index22 alt2">
23</div>
<div class="line number24 index23 alt1">
24</div>
<div class="line number25 index24 alt2">
25</div>
<div class="line number26 index25 alt1">
26</div>
<div class="line number27 index26 alt2">
27</div>
<div class="line number28 index27 alt1">
28</div>
<div class="line number29 index28 alt2">
29</div>
<div class="line number30 index29 alt1">
30</div>
<div class="line number31 index30 alt2">
31</div>
<div class="line number32 index31 alt1">
32</div>
<div class="line number33 index32 alt2">
33</div>
<div class="line number34 index33 alt1">
34</div>
<div class="line number35 index34 alt2">
35</div>
<div class="line number36 index35 alt1">
36</div>
<div class="line number37 index36 alt2">
37</div>
<div class="line number38 index37 alt1">
38</div>
<div class="line number39 index38 alt2">
39</div>
<div class="line number40 index39 alt1">
40</div>
<div class="line number41 index40 alt2">
41</div>
<div class="line number42 index41 alt1">
42</div>
<div class="line number43 index42 alt2">
43</div>
<div class="line number44 index43 alt1">
44</div>
<div class="line number45 index44 alt2">
45</div>
<div class="line number46 index45 alt1">
46</div>
<div class="line number47 index46 alt2">
47</div>
<div class="line number48 index47 alt1">
48</div>
<div class="line number49 index48 alt2">
49</div>
<div class="line number50 index49 alt1">
50</div>
<div class="line number51 index50 alt2">
51</div>
<div class="line number52 index51 alt1">
52</div>
<div class="line number53 index52 alt2">
53</div>
<div class="line number54 index53 alt1">
54</div>
<div class="line number55 index54 alt2">
55</div>
<div class="line number56 index55 alt1">
56</div>
<div class="line number57 index56 alt2">
57</div>
<div class="line number58 index57 alt1">
58</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2">
<code class="cpp preprocessor">#include <unistd.h> </code>
</div>
<div class="line number2 index1 alt1">
<code class="cpp preprocessor">#include <stdlib.h> </code>
</div>
<div class="line number3 index2 alt2">
<code class="cpp preprocessor">#include <stdio.h> </code>
</div>
<div class="line number4 index3 alt1">
<code class="cpp preprocessor">#include <string.h> </code>
</div>
<div class="line number5 index4 alt2">
<code class="cpp preprocessor">#include <sys/shm.h> </code>
</div>
<div class="line number6 index5 alt1">
<code class="cpp preprocessor">#include "shmdata.h" </code>
</div>
<div class="line number7 index6 alt2">
<code class="cpp spaces"> </code>
</div>
<div class="line number8 index7 alt1">
<code class="cpp color1 bold">int</code> <code class="cpp plain">main() </code>
</div>
<div class="line number9 index8 alt2">
<code class="cpp plain">{ </code>
</div>
<div class="line number10 index9 alt1">
<code class="cpp spaces"> </code><code class="cpp color1 bold">int</code> <code class="cpp plain">running = 1; </code>
</div>
<div class="line number11 index10 alt2">
<code class="cpp spaces"> </code><code class="cpp keyword bold">void</code> <code class="cpp plain">*shm = NULL; </code>
</div>
<div class="line number12 index11 alt1">
<code class="cpp spaces"> </code><code class="cpp keyword bold">struct</code> <code class="cpp plain">shared_use_st *shared = NULL; </code>
</div>
<div class="line number13 index12 alt2">
<code class="cpp spaces"> </code><code class="cpp color1 bold">char</code> <code class="cpp plain">buffer;</code><code class="cpp comments">//用于保存输入的文本 </code>
</div>
<div class="line number14 index13 alt1">
<code class="cpp spaces"> </code><code class="cpp color1 bold">int</code> <code class="cpp plain">shmid; </code>
</div>
<div class="line number15 index14 alt2">
<code class="cpp spaces"> </code><code class="cpp comments">//创建共享内存 </code>
</div>
<div class="line number16 index15 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">shmid = shmget((key_t)1234, </code><code class="cpp keyword bold">sizeof</code><code class="cpp plain">(</code><code class="cpp keyword bold">struct</code> <code class="cpp plain">shared_use_st), 0666|IPC_CREAT); </code>
</div>
<div class="line number17 index16 alt2">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(shmid == -1) </code>
</div>
<div class="line number18 index17 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number19 index18 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">fprintf</code><code class="cpp plain">(stderr, </code><code class="cpp string">"shmget failed\n"</code><code class="cpp plain">); </code>
</div>
<div class="line number20 index19 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">exit</code><code class="cpp plain">(EXIT_FAILURE); </code>
</div>
<div class="line number21 index20 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number22 index21 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//将共享内存连接到当前进程的地址空间 </code>
</div>
<div class="line number23 index22 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">shm = shmat(shmid, (</code><code class="cpp keyword bold">void</code><code class="cpp plain">*)0, 0); </code>
</div>
<div class="line number24 index23 alt1">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(shm == (</code><code class="cpp keyword bold">void</code><code class="cpp plain">*)-1) </code>
</div>
<div class="line number25 index24 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number26 index25 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">fprintf</code><code class="cpp plain">(stderr, </code><code class="cpp string">"shmat failed\n"</code><code class="cpp plain">); </code>
</div>
<div class="line number27 index26 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">exit</code><code class="cpp plain">(EXIT_FAILURE); </code>
</div>
<div class="line number28 index27 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number29 index28 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"Memory attached at %X\n"</code><code class="cpp plain">, (</code><code class="cpp color1 bold">int</code><code class="cpp plain">)shm); </code>
</div>
<div class="line number30 index29 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//设置共享内存 </code>
</div>
<div class="line number31 index30 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">shared = (</code><code class="cpp keyword bold">struct</code> <code class="cpp plain">shared_use_st*)shm; </code>
</div>
<div class="line number32 index31 alt1">
<code class="cpp spaces"> </code><code class="cpp keyword bold">while</code><code class="cpp plain">(running)</code><code class="cpp comments">//向共享内存中写数据 </code>
</div>
<div class="line number33 index32 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number34 index33 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本 </code>
</div>
<div class="line number35 index34 alt2">
<code class="cpp spaces"> </code><code class="cpp keyword bold">while</code><code class="cpp plain">(shared->written == 1) </code>
</div>
<div class="line number36 index35 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number37 index36 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">sleep(1); </code>
</div>
<div class="line number38 index37 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"Waiting...\n"</code><code class="cpp plain">); </code>
</div>
<div class="line number39 index38 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number40 index39 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//向共享内存中写入数据 </code>
</div>
<div class="line number41 index40 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">printf</code><code class="cpp plain">(</code><code class="cpp string">"Enter some text: "</code><code class="cpp plain">); </code>
</div>
<div class="line number42 index41 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">fgets</code><code class="cpp plain">(buffer, BUFSIZ, stdin); </code>
</div>
<div class="line number43 index42 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">strncpy</code><code class="cpp plain">(shared->text, buffer, TEXT_SZ); </code>
</div>
<div class="line number44 index43 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//写完数据,设置written使共享内存段可读 </code>
</div>
<div class="line number45 index44 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">shared->written = 1; </code>
</div>
<div class="line number46 index45 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//输入了end,退出循环(程序) </code>
</div>
<div class="line number47 index46 alt2">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(</code><code class="cpp functions bold">strncmp</code><code class="cpp plain">(buffer, </code><code class="cpp string">"end"</code><code class="cpp plain">, 3) == 0) </code>
</div>
<div class="line number48 index47 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">running = 0; </code>
</div>
<div class="line number49 index48 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number50 index49 alt1">
<code class="cpp spaces"> </code><code class="cpp comments">//把共享内存从当前进程中分离 </code>
</div>
<div class="line number51 index50 alt2">
<code class="cpp spaces"> </code><code class="cpp keyword bold">if</code><code class="cpp plain">(shmdt(shm) == -1) </code>
</div>
<div class="line number52 index51 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">{ </code>
</div>
<div class="line number53 index52 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">fprintf</code><code class="cpp plain">(stderr, </code><code class="cpp string">"shmdt failed\n"</code><code class="cpp plain">); </code>
</div>
<div class="line number54 index53 alt1">
<code class="cpp spaces"> </code><code class="cpp functions bold">exit</code><code class="cpp plain">(EXIT_FAILURE); </code>
</div>
<div class="line number55 index54 alt2">
<code class="cpp spaces"> </code><code class="cpp plain">} </code>
</div>
<div class="line number56 index55 alt1">
<code class="cpp spaces"> </code><code class="cpp plain">sleep(2); </code>
</div>
<div class="line number57 index56 alt2">
<code class="cpp spaces"> </code><code class="cpp functions bold">exit</code><code class="cpp plain">(EXIT_SUCCESS); </code>
</div>
<div class="line number58 index57 alt1">
<code class="cpp plain">} </code>
</div>
</div>
</td>
</tr></tbody></table>
</div>
</div>
<div class="codetool" id="codetool">
<div class="code_n">
<textarea></textarea>
</div>
</div>
</div>
<p>
再来看看运行的结果:</p>
<p>
<img title="详解Linux进程间通信——使用共享内存" alt="详解Linux进程间通信——使用共享内存" src="https://zhuji.jb51.net/uploads/img/202305/b8be0b30e64eead8b2b2ae63b46f4975.jpg"></p>
<p>
分析:</p>
<p>
1、程序shmread创建共享内存,然后将它连接到自己的地址空间。在共享内存的开始处使用了一个结构struct_use_st。该结构中有个标志written,当共享内存中有其他进程向它写入数据时,共享内存中的written被设置为0,程序等待。当它不为0时,表示没有进程对共享内存写入数据,程序就从共享内存中读取数据并输出,然后重置设置共享内存中的written为0,即让其可被shmwrite进程写入数据。</p>
<p>
2、程序shmwrite取得共享内存并连接到自己的地址空间中。检查共享内存中的written,是否为0,若不是,表示共享内存中的数据还没有被完,则等待其他进程读取完成,并提示用户等待。若共享内存的written为0,表示没有其他进程对共享内存进行读取,则提示用户输入文本,并再次设置共享内存中的written为1,表示写完成,其他进程可对共享内存进行读操作。</p>
<p>
<span><strong>四、关于前面的例子的安全性讨论</strong></span></p>
<p>
这个程序是不安全的,当有多个程序同时向共享内存中读写数据时,问题就会出现。可能你会认为,可以改变一下written的使用方式,例如,只有当written为0时进程才可以向共享内存写入数据,而当一个进程只有在written不为0时才能对其进行读取,同时把written进行加1操作,读取完后进行减1操作。这就有点像文件锁中的读写锁的功能。咋看之下,它似乎能行得通。但是这都不是原子操作,所以这种做法是行不能的。试想当written为0时,如果有两个进程同时访问共享内存,它们就会发现written为0,于是两个进程都对其进行写操作,显然不行。当written为1时,有两个进程同时对共享内存进行读操作时也是如些,当这两个进程都读取完是,written就变成了-1.</p>
<p>
要想让程序安全地执行,就要有一种进程同步的进制,保证在进入临界区的操作是原子操作。例如,可以使用前面所讲的信号量来进行进程的同步。因为信号量的操作都是原子性的。</p>
<p>
<span><strong>五、使用共享内存的优缺点</strong></span></p>
<p>
1、优点:我们可以看到使用共享内存进行进程间的通信真的是非常方便,而且函数的接口也简单,数据的共享还使进程间的数据不用传送,而是直接访问内存,也加快了程序的效率。同时,它也不像匿名管道那样要求通信的进程有一定的父子关系。</p>
<p>
2、缺点:共享内存没有提供同步的机制,这使得我们在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作。</p>
<p>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。</p>
<p>
原文链接:http://blog.csdn.net/ljianhui/article/details/10253345</p>
頁:
[1]