1. 程式人生 > >使用共享記憶體實現一個程序寫檔案,兩個程序讀檔案

使用共享記憶體實現一個程序寫檔案,兩個程序讀檔案

主要功能:讀取任意的檔案,大小不限(不超過共享記憶體設定的大小,一般為8k,但可手動重新設定,這已經很大了。),執行後兩個或多個讀程序可同時讀取該檔案並在終端列印。

要實現該功能,首先你得了解共享記憶體的搭建,有四個函式,分別為shmget,shmat,shmdt,shmctl,他們的作用如下:

1、shmget函式 該函式用來建立共享記憶體,它的原型為: [cpp] view plain copy  print?
  1. int shmget(key_t key, size_t size, int shmflg);  
第一個引數,與訊號量的semget函式一樣,程式需要提供一個引數key(非0整數),它有效地為共享記憶體段命名,shmget函式成功時返回一個與key相關的共享記憶體識別符號(非負整數),用於後續的共享記憶體函式。呼叫失敗返回-1. 不相關的程序可以通過該函式的返回值訪問同一共享記憶體,它代表程式可能要使用的某個資源,程式對所有共享記憶體的訪問都是間接的,程式先通過呼叫shmget函式並提供一個鍵,再由系統生成一個相應的共享記憶體識別符號(shmget函式的返回值),只有shmget函式才直接使用訊號量鍵,所有其他的訊號量函式使用由semget函式返回的訊號量識別符號。 第二個引數,size以位元組為單位指定需要共享的記憶體容量 第三個引數,shmflg是許可權標誌,它的作用與open函式的mode引數一樣,如果要想在key標識的共享記憶體不存在時,建立它的話,可以與IPC_CREAT做或操作。共享記憶體的許可權標誌與檔案的讀寫許可權一樣,舉例來說,0644,它表示允許一個程序建立的共享記憶體被記憶體建立者所擁有的程序向共享記憶體讀取和寫入資料,同時其他使用者建立的程序只能讀取共享記憶體。 2、shmat函式
第一次建立完共享記憶體時,它還不能被任何程序訪問,shmat函式的作用就是用來啟動對該共享記憶體的訪問,並把共享記憶體連線到當前程序的地址空間。它的原型如下: [cpp] view plain copy  print?
  1. void *shmat(int shm_id, constvoid *shm_addr, int shmflg);  
第一個引數,shm_id是由shmget函式返回的共享記憶體標識。 第二個引數,shm_addr指定共享記憶體連線到當前程序中的地址位置,通常為空,表示讓系統來選擇共享記憶體的地址。 第三個引數,shm_flg是一組標誌位,通常為0。 呼叫成功時返回一個指向共享記憶體第一個位元組的指標,如果呼叫失敗返回-1. 3、shmdt函式
該函式用於將共享記憶體從當前程序中分離。注意,將共享記憶體分離並不是刪除它,只是使該共享記憶體對當前程序不再可用。它的原型如下: [cpp] view plain copy  print?
  1. int shmdt(constvoid *shmaddr);  
引數shmaddr是shmat函式返回的地址指標,呼叫成功時返回0,失敗時返回-1. 4、shmctl函式 與訊號量的semctl函式一樣,用來控制共享記憶體,它的原型如下: [cpp] view plain copy  print?
  1. int shmctl(int shm_id, int command, 
    struct shmid_ds *buf);  
第一個引數,shm_id是shmget函式返回的共享記憶體識別符號。 第二個引數,command是要採取的操作,它可以取下面的三個值 :     IPC_STAT:把shmid_ds結構中的資料設定為共享記憶體的當前關聯值,即用共享記憶體的當前關聯值覆蓋shmid_ds的值。     IPC_SET:如果程序有足夠的許可權,就把共享記憶體的當前關聯值設定為shmid_ds結構中給出的值
    IPC_RMID:刪除共享記憶體段
第三個引數,buf是一個結構指標,它指向共享記憶體模式和訪問許可權的結構。 shmid_ds結構至少包括以下成員: [cpp] view plain copy  print?
  1. struct shmid_ds  
  2. {  
  3.     uid_t shm_perm.uid;  
  4.     uid_t shm_perm.gid;  
  5.     mode_t shm_perm.mode;  
  6. };  

具體思路:先寫後讀,寫程序先開啟檔案,然後往shmemory共享記憶體內寫入檔案,讀程序直接從共享記憶體中讀檔案,並打印出來。

三個檔案:shmwrite.c (寫程序) shmread.c(讀程序,可以有多個)  sharemry.h(標頭檔案)

先看標頭檔案sharemry.h:


定義了flag是否可讀的標誌,size寫入檔案的大小,free_status是否最後一個讀程序,text是一個可變陣列,根據開啟的檔案大小開闢記憶體。無論是端還是寫端,都必須先掛載到同一共享記憶體上。

可變陣列:

text[0]結構

經常遇到的結構形狀如下:

struct buffer
{
    int text_len;   //長度
    char text[0];  //起始地址
};

  在這個結構中,text是一個數組名;但該陣列沒有元素;該陣列的真實地址緊隨結構體buffer之後,而這個地址就是結構體後面資料的地址(如果給這個結構體分配的內容大於這個結構體實際大小,後面多餘的部分就是這個text的內容);這種宣告方法可以巧妙的實現C語言裡的陣列擴充套件。


下圖是shmwrite.c寫程序原始碼:


掛載到共享記憶體之後,開始讀檔案並寫入共享記憶體


寫入完成,將程式和共享記憶體解除安裝,也即脫離。


最後是shmread.c:


接上圖


這裡就會用到flag,有兩個或多個程序同時讀同一個共享記憶體時,每個讀程序都會去掛載這塊建立好的共享記憶體,但是有個隱藏的bug,共享記憶體是公用的一塊,如果每個讀程序都去shmctl共享記憶體的話,會出現錯誤,類似於記憶體洩露。所以標誌flag保證最後一個讀程序退出時才刪除共享記憶體。