Linux 共享內存編程


共享內存允許系統內兩個或多個進程共享同一塊內存空間,並且數據不用在客戶進程和服務器進程間復制,因此共享內存是通信速度最快的一種IPC。

實現的機制簡單描述如下:一個進程在系統中申請開辟了一塊共享內存空間,然后使用這個共享內存空間的各個進程分別打開這個共享內存空間,並將這個內存空間映射到自己的進程空間上,這樣各個進程就可以共同使用這個共享內存空間,就如同使用自己進程地址空間的內存一樣。

要實現共享內存空間,內核做了許多工作:比如給每個共享內存塊分發一個“身份證”、允許用戶進程將共享內存映射到各自的地址空間上、在進程提出申請以后將共享內存和進程地址空間脫離,並在適當的時候講共享內存刪除,讓其回到可以被創建的狀態。

用戶利用共享內存實現進程間的通信,實際上就是使用內核提供的服務完成對共享內存的建立、映射、脫離、刪除等。當建立並映射成功以后,進程間就能通過共享內存實現數據的交互。下面就分別介紹內核提供的服務:

int shmget(key_t key, size_t size, int shmflg)

void *shmat(int shmid,const void* shmaddr,int shmflg);

int shmdt(const void* shmaddr);

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

 

shmget 函數

shmget 函數實現共享內存的建立或者打開。當共享內存的鍵值key 尚未存在時,調用這個函數並且指定shmflg 參數為IPC_CREAT 可以創建一個大小為 size 的共享內存空間。假設key指定的共享內存已經存在,調用這個函數可以打開這個共享內存,但不會創建。鍵值的獲取可以利用 ftok(),該函數的使用在博主的另一篇文章里http://www.cnblogs.com/linzizhang/p/4544794.html中有介紹。

shmat 函數

該函數將一個共享內存空間映射到調用進程的地址空間上,並且返回在進程地址空間中的地址。用戶拿到改地址后就可以通過這個地址間接的訪問共享內存。shmid 參數就是shmget 函數的返回值,shmaddr 參數實際上是指出了共享內存映射到進程地址空間上的位置,但是我們一般不會指定這個地址,而是令其為NULL ,讓內核選擇一個合適的地址。shmflg 參數是配合着shmaddr 參數使用的,在shmaddr 為NULL時就變得沒有實際意義,因此通常指定為0。

shmdt 函數

這個函數將一個進程已經映射了的共享內存脫離進程地址空間。shmaddr 參數就是在進程地址空間的地址,實際就是shmat 函數的返回值。

shmctl 函數

此函數實際上有很多的功能,但是我們通長用它將一個已經創建了的共享內存刪除,所謂刪除實際就是將它放回可以被創建的共享內存隊列中。指定cmd 參數為IPC_RMID,就可以將shmid鍵值指定的共享內存刪除,而buf實際上是可以獲取這共享內存在內核中的狀態,如果不想了解可以指定為0。

共享內存通信使用到的系統服務就這么多,下面給出一個測試范例。該范例由兩個進程組成,進程write將鍵盤上輸入的字符串存儲到共享內存,read進程將共享內存中的數據讀出來,再西融入顯示器顯示。

write進程代碼:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>

#define TEXT_SZ 2048

struct shared_use_st
{
    int written_by_you;
    char some_text[TEXT_SZ];      
};

int main(int argc,char **argv)
{
     
    key_t key;
    int shmid;  
    struct shared_use_st *space;
    int running  = 1;
    char buffer[TEXT_SZ];
    //creat shared memory
    key = ftok("/home/application/shared_memory",2);

    shmid = shmget(key,sizeof(struct shared_use_st),IPC_CREAT);

    //attach share memory to space
    space = (struct shared_use_st *)shmat(shmid,NULL,0);          

    //write datas to space
    while(running)
    {
        while(space->written_by_you==1)
        {
            sleep(1);    
        }
        printf("Input strings:");
        fgets(buffer,TEXT_SZ,stdin);
        strncpy(space->some_text,buffer,TEXT_SZ);
        space->written_by_you = 1;
        if(strncmp(buffer,"end",3)==0)
        {
            running = 0;    
        }
       
    }
    
    
    //dis_attach to space
    shmdt((const void *)space);
    //distroy shared memory
  //  shmctl(shmid,IPC_RMID);

    return 0;
}
View Code

read進程代碼:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>

#define TEXT_SZ 2048
struct shared_use_st
{
    int written_by_you;    //標志用來標明write進程是否寫入了數據 written_by_you==1,寫入數據,且read進程還沒讀走
    char some_text[TEXT_SZ];      
};

int main()
{
    key_t key;
    int shmid;
    struct shared_use_st *space;
    int running = 1;
    char buffer[TEXT_SZ];
    //打開共享內存
    key = ftok("/home/application/shared_memory",2);

    shmid = shmget(key,sizeof(struct shared_use_st),IPC_CREAT);
    
    //映射共享內存
    space = (struct shared_use_st *)shmat(shmid,NULL,0);    
    
    //讀取數據
    while(running)
    {
        if(space->written_by_you==1)
        {
            strncpy(buffer,space->some_text,TEXT_SZ);
            space->written_by_you = 0;
            printf("Recieved string :%s",buffer);    
        }    
        if(strncmp(buffer,"end",3)==0)
        {
            running = 0;    
        }
        
    }
    
    //斷開映射
    shmdt((const void *)space);
    
    //刪除共享內存
    shmctl(shmid,IPC_RMID,0);
    
    return 0;
        
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM