转:共享内存的编程实现
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 }
原文链接:http://blog.csdn.net/pcliuguangtao/article/details/6526119