linux进程通讯-共享内存

来源:互联网 发布:长图截屏软件 编辑:程序博客网 时间:2024/05/21 07:04

共享内存:
    共享内存区域是被多个进程共享的一部分物理内存.
    不同的进程可以通过共享内存通信,是进程间共享数据的一种最快的方法.
    一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容
    (比如你把你家的保险箱密码告诉我,那我们就可以通过保险箱共享money,你一放进去money,我就可以 

    立马收到你的money了!!!!) 
   实现:
       ->创建共享内存,使用shmget函数
       ->映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数 
 当一个进程不再需要共享的内存段时,它将会把内存段从其地址空间中脱离,调用shmdt函数
 Example: sharedMemory.c

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <stdio.h>#include <stdlib.h>#define BUFSZ 2048int main(){ int shmid; char *shmadd;  if((shmid=shmget(IPC_PRIVATE,BUFSZ,0666))<0) {  perror("shmget");  exit(1); } else {  printf("created shared-memory: %d\n",shmid);  system("ipcs -m"); }   if((shmadd=shmat(shmid,0,0))<(char *)0) {  perror("shmat");  exit(1); } else {  printf("attached shared-memory\n");  system("ipcs -m"); }  if((shmdt(shmadd))<0) {  perror("shmdt");  exit(1); } else {  printf("deleted shared-memory\n");  system("ipcs -m"); }  exit(0);}

 

 

消息队列:
 消息队列就是消息的一个链表,它允许一个或多个进程向它写消息,一个或多个进程从中读消息。具有一

    定的FIFO特性,但是可实现消息的随机查询,这些消息存在于内核中,由“队列ID”来标识
 实现: 创建和打开队列、添加消息、读取消息、控制消息四种操作
 msgget:创建和打开队列,消息数量受系统限制
 msgsnd:添加消息,将消息添加到消息队列尾部
 msgrcv:读取消息
 msgctl:控制消息队列
 Example: msg.c

#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#define BUFSZ 512struct message{   long msg_type;   char msg_text[BUFSZ];};int main(){   int qid;   key_t key;   int len;   struct message msg; if((key=ftok(".",'a'))==-1) {    perror("ftok");    exit(1); } if((qid=msgget(key,IPC_CREAT|0666))==-1) {    perror("msgget");    exit(1); } printf("opened queue %d\n",qid); puts("Please enter the message to queue:"); if((fgets(msg.msg_text,BUFSZ,stdin))==NULL) {   puts("no message");    exit(1); } msg.msg_type = getpid(); len = strlen(msg.msg_text); if((msgsnd(qid,&msg,len,0))<0) {    perror("message posted");    exit(1); } if(msgrcv(qid,&msg,BUFSZ,0,0)<0) {    perror("msgrcv");    exit(1); } printf("message is:%s\n",msg.msg_text); if((msgctl(qid,IPC_RMID,NULL))<0) {    perror("msgctl");    exit(1); } exit(0);}

/*共享内存允许两个或多个进程进程共享同一块内存(这块内存会映射到各个进程自己独立的地址空间)  从而使得这些进程可以相互通信。  在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 67483int 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 67483int 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 200typedef 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;            }


原创粉丝点击