Linux共享記憶體(二)

maojunxu發表於2018-03-09

Linux共享記憶體程式設計例項

原文連結:http://blog.csdn.net/pcliuguangtao/article/details/6526119

複製程式碼
/*共享記憶體允許兩個或多個程式程式共享同一塊記憶體(這塊記憶體會對映到各個程式自己獨立的地址空間)
  從而使得這些程式可以相互通訊。
  在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;
        
    }
複製程式碼

 


相關文章