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