1 /*共享内存允许两个或多个进程进程共享同一块内存(这块内存会映射到各个进程自己独立的地址空间)
2 从而使得这些进程可以相互通信。
3 在GNU/Linux中所有的进程都有唯一的虚拟地址空间,而共享内存应用编程接口API允许一个进程使
4 用公共内存区段。但是对内存的共享访问其复杂度也相应增加。共享内存的优点是简易性。
5 使用消息队列时,一个进程要向队列中写入消息,这要引起从用户地址空间向内核地址空间的一次复制,
6 同样一个进程进行消息读取时也要进行一次复制。共享内存的优点是完全省去了这些操作。
7 共享内存会映射到进程的虚拟地址空间,进程对其可以直接访问,避免了数据的复制过程。
8 因此,共享内存是GNU/Linux现在可用的最快速的IPC机制。
9 进程退出时会自动和已经挂接的共享内存区段分离,但是仍建议当进程不再使用共享区段时
10 调用shmdt来卸载区段。
11 注意,当一个进程分支出父进程和子进程时,父进程先前创建的所有共享内存区段都会被子进程继承。
12 如果区段已经做了删除标记(在前面以IPC——RMID指令调用shmctl),而当前挂接数已经变为0,
13 这个区段就会被移除。
14 */
15 /*
16 shmget( ) 创建一个新的共享内存区段
17 取得一个共享内存区段的描述符
18 shmctl( ) 取得一个共享内存区段的信息
19 为一个共享内存区段设置特定的信息
20 移除一个共享内存区段
21 shmat( ) 挂接一个共享内存区段
22 shmdt( ) 于一个共享内存区段的分离
23 */
24 //创建一个共享内存区段,并显示其相关信息,然后删除该内存共享区
25 #include <stdio.h>
26 #include <unistd.h> //getpagesize( )
27 #include <sys/ipc.h>
28 #include <sys/shm.h>
29 #define MY_SHM_ID 67483
30 int main( )
31 {
32 //获得系统中页面的大小
33 printf( "page size=%d/n",getpagesize( ) );
34 //创建一个共享内存区段
35 int shmid,ret;
36 shmid=shmget( MY_SHM_ID,4096,0666|IPC_CREAT );
37 //创建了一个4KB大小共享内存区段。指定的大小必须是当前系统架构
38 //中页面大小的整数倍
39 if( shmid>0 )
40 printf( "Create a shared memory segment %d/n",shmid );
41 //获得一个内存区段的信息
42 struct shmid_ds shmds;
43 //shmid=shmget( MY_SHM_ID,0,0 );//示例怎样获得一个共享内存的标识符
44 ret=shmctl( shmid,IPC_STAT,&shmds );
45 if( ret==0 )
46 {
47 printf( "Size of memory segment is %d/n",shmds.shm_segsz );
48 printf( "Numbre of attaches %d/n",( int )shmds.shm_nattch );
49 }
50 else
51 {
52 printf( "shmctl( ) call failed/n" );
53 }
54 //删除该共享内存区
55 ret=shmctl( shmid,IPC_RMID,0 );
56 if( ret==0 )
57 printf( "Shared memory removed /n" );
58 else
59 printf( "Shared memory remove failed /n" );
60 return 0;
61 }
62
63 //共享内存区段的挂载,脱离和使用
64 //理解共享内存区段就是一块大内存
65 #include <stdio.h>
66 #include <sys/shm.h>
67 #include <sys/ipc.h>
68 #include <errno.h>
69 #define MY_SHM_ID 67483
70 int main( )
71 {
72 //共享内存区段的挂载和脱离
73 int shmid,ret;
74 void* mem;
75 shmid=shmget( MY_SHM_ID,0,0 );
76 if( shmid>=0 )
77 {
78 mem=shmat( shmid,( const void* )0,0 );
79 //shmat()返回进程地址空间中指向区段的指针
80 if( ( int )mem!=-1 )
81 {
82 printf( "Shared memory was attached in our address space at %p/n",mem );
83 //向共享区段内存写入数据
84 strcpy( ( char* )mem,"This is a test string./n" );
85 printf( "%s/n",(char*)mem );
86 //脱离共享内存区段
87 ret=shmdt( mem );
88 if( ret==0 )
89 printf( "Successfully detached memory /n" );
90 else
91 printf( "Memory detached failed %d/n",errno );
92 }
93 else
94 printf( "shmat( ) failed/n" );
95
96 }
97 else
98 printf( "shared memory segment not found/n" );
99 return 0;
100 }
101 /*内存共享区段与旗语和消息队列不同,一个区段可以被锁定。
102 被锁定的区段不允许被交换出内存。这样做的优势在于,与其
103 把内存区段交换到文件系统,在某个应用程序调用时再交换回内存,
104 不如让它一直处于内存中,且对多个应用程序可见。从提升性能的角度
105 来看,很重要的。
106 */
107 int shmid;
108 //...
109 shmid=shmget( MY_SHM_ID,0,0 );
110 ret=shmctl( shmid,SHM_LOCK,0 );
111 if( ret==0 )
112 printf( "Locked!/n" );
113 ////////////////////////////////////////////////////////////////////////
114 /*使用旗语协调共享内存的例子
115 使用和编译命令
116 gcc -Wall test.c -o test
117 ./test create
118 ./test use a &
119 ./test use b &
120 ./test read &
121 ./test remove
122 */
123 #include <stdio.h>
124 #include <sys/shm.h>
125 #include <sys/ipc.h>
126 #include <sys/sem.h>
127 #include <string.h>
128 #include <stdlib.h>
129 #include <unistd.h>
130 #define MY_SHM_ID 34325
131 #define MY_SEM_ID 23234
132 #define MAX_STRING 200
133 typedef struct
134 {
135 int semID;
136 int counter;
137 char string[ MAX_STRING+1 ];
138 }MY_BLOCK_T;
139 int main(int argc,char** argv)
140 {
141 int shmid,ret,i;
142 MY_BLOCK_T* block;
143 struct sembuf sb;
144 char user;
145 //make sure there is a command
146 if( argc>=2 )
147 {
148 //create the shared memory segment and init it
149 //with the semaphore
150 if( !strncmp(argv[ 1 ],"create",6) )
151 {
152 //create the shared memory segment and semaphore
153 printf( "Creating the shared memory/n" );
154 shmid=shmget( MY_SHM_ID,sizeof( MY_BLOCK_T ),( IPC_CREAT|0666 ) );
155 block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );
156 block->counter=0;
157 //create the semaphore and init
158 block->semID=semget(MY_SEM_ID,1,( IPC_CREAT|0666 ));
159 sb.sem_num=0;
160 sb.sem_op=1;
161 sb.sem_flg=0;
162 semop( block->semID,&sb,1 );
163 //now detach the segment
164 shmdt( ( void* )block );
165 printf( "Create the shared memory and semaphore successuflly/n" );
166
167 }
168 else if( !strncmp(argv[ 1 ],"use",3) )
169 {
170 /*use the segment*/
171 //must specify also a letter to write to the buffer
172 if( argc<3 ) exit( -1 );
173 user=( char )argv[ 2 ][ 0 ];
174 //grab the segment
175 shmid=shmget( MY_SHM_ID,0,0 );
176 block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );
177
178 /*##########重点就是使用旗语对共享区的访问###########*/
179 for( i=0;i<100;++i )
180 {
181 sleep( 1 ); //设置成1s就会看到 a/b交替出现,为0则a和b连续出现
182 //grab the semaphore
183 sb.sem_num=0;
184 sb.sem_op=-1;
185 sb.sem_flg=0;
186 if( semop( block->semID,&sb,1 )!=-1 )
187 {
188 //write the letter to the segment buffer
189 //this is our CRITICAL SECTION
190 block->string[ block->counter++ ]=user;
191
192 sb.sem_num=0;
193 sb.sem_op=1;
194 sb.sem_flg=0;
195 if( semop( block->semID,&sb,1 )==-1 )
196 printf( "Failed to release the semaphore/n" );
197
198 }
199 else
200 printf( "Failed to acquire the semaphore/n" );
201 }
202
203 //do some clear work
204 ret=shmdt(( void*)block);
205
206 }
207 else if( !strncmp(argv[ 1 ],"read",4) )
208 {
209 //here we will read the buffer in the shared segment
210 shmid=shmget( MY_SHM_ID,0,0 );
211 if( shmid!=-1 )
212 {
213 block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );
214 block->string[ block->counter+1 ]=0;
215 printf( "%s/n",block->string );
216 printf( "Length=%d/n",block->counter );
217 ret=shmdt( ( void*)block );
218 }
219 else
220 printf( "Unable to read segment/n" );
221
222 }
223 else if( !strncmp(argv[ 1 ],"remove",6) )
224 {
225 shmid=shmget( MY_SHM_ID,0,0 );
226 if( shmid>=0 )
227 {
228 block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );
229 //remove the semaphore
230 ret=semctl( block->semID,0,IPC_RMID );
231 if( ret==0 )
232 printf( "Successfully remove the semaphore /n" );
233 //remove the shared segment
234 ret=shmctl( shmid,IPC_RMID,0 );
235 if( ret==0 )
236 printf( "Successfully remove the segment /n" );
237 }
238 }
239 else
240 printf( "Unkonw command/n" );
241 }
242 return 0;
243
244 }