Linux 共享内存介绍及实现代码
共享内存是进程间通信中最简单的方式之一。共享内存允许两个或多个进程进程共享同一块内存(这块内存会映射到各个进程自己独立的地址空间)从而使得这些进程可以相互通信。在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; }
内存共享区段与旗语和消息队列不同,一个区段可以被锁定。被锁定的区段不允许被交换出内存。这样做的优势在于,与其把内存区段交换到文件系统,在某个应用程序调用时再交换回内存,不如让它一直处于内存中,且对多个应用程序可见。从提升性能的角度来看,很重要的。
#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; }
linux下free命令显示的内存使用情况分析 哪位前辈给解释下linux下虚拟内存和物理内存的关系! Linux内存文件系统(ramdisk)的三种实现方式 linux下内存泄露检测工具 mtrace 如果记录.so文件中的内存信息 linux内存文件系统ramfs实现原理 linux中程序内存泄露如何界定呢?这样算内存泄露吗? linux下进程占用内存空间详解 有人熟悉DMA吗?我要实现内存中的内存的“搬动”。(LINUX) Linux/Centos/Ubuntu清除系统缓存释放内存命令介绍 如何让linux没有到达内存瓶颈时回收内存页并占用最少资源 linux下进程间通信:共享内存原理及具体用法举例(基于c/c++语言) 请教关于linux内存管理问题,如何给定义的变量指定固定内存段 在Linux上用C语言编写的函数里面申请了一块内存,并且返回这块内存,最终它需要释放吗? 大家好,我想问下有人用过"linux进程的内存使用解析"中推荐使用的"Ben Maurer写的perl脚本"查看内存么 在SUSE linux下jar文档的运行,提示内存泄露,指定最大最小内存后只能在十几分钟才能打开,求各位大虾指点! 我的redhat linux7.3因为内存有些少,所以我想随时查看内存的使用情况该如何去做,还有我想关掉(而不是切换)图形界面应该用什么命令 请教!Linux系统C开发的程序,为什么我的程序运行时内存持续增长,程序退出后内存也没有降低? 虚拟机上的Linux怎么修改Linux内存 问个LINUX内存分配的问题。 linux9.0下内存占用一直是95%以上怎么解决