使用共享記憶體基本分四個步驟:
獲得共享記憶體:shmget()->對映共享記憶體shmat() -->解除對映shmdt()-->刪除共享記憶體shmctl()
於是自己在網上找來了乙個例子看了下,並且用虛擬機器單獨跑了下共享記憶體的經典例程看了下,才知道了自己的問題出現**了 ,
發現有時候只要自己親自將程式一步一步的去測,才知道問題的根源在**,結果出來的時候才恍然大悟
這是我在我開發用的乙個共享記憶體函式模組找了出來分析了下:
//#define helper_filename_ftok"/dev/ttyama0"
#define helper_filename_ftok"/dev/ttys000"
int openshm(const char *pathname, int proj_id, size_t size)
if ((sid = shmget (shmkey, size, 0)) == -1)
return (sid);
}int openshmenv()
}//對映共享記憶體
if(null == shmaddr)
}//建立訊號量
if(-1 == semid)
}return 0;
}這個是我當時在我海思3520d中執行的共享記憶體塊的一部分** ,我在執行的時候當我進行解碼的執行緒的時候就會出現(open shm failed!)這個問題。
當時很納悶我看了下**也沒有寫錯,我發現在獲取共享記憶體之前我們有乙個ftok函式。
因為系統建立ipc通訊(如訊息佇列、共享記憶體時)必須指定乙個id值。通常情況下,該id值通過ftok函式得到。
ftok原型如下:
key_t ftok( char * fname, int id )
fname就時你指定的檔名(該檔案必須是存在而且可以訪問的),id是子序號,
雖然為int,但是只有8個位元被使用(0-255)。
當成功執行的時候,乙個key_t值將會被返回,否則 -1 被返回。
於是我發現我們ftok函式中用的路徑為(#define helper_filename_ftok"/dev/ttys000"),於是我進入到我的根檔案系統中,
用命令cat /dev/
我發現其實我們共享記憶體的指定檔案路徑是 /dev/ttyama0 ,於是恍然大悟,難怪程式跑的時候開啟共享記憶體失敗!
於是我把#define helper_filename_ftok"/dev/ttys000"
換成 #define helper_filename_ftok"/dev/ttyama0"
再重新編譯下燒進去跑的時候,發現問題解決了 。
我們用乙個簡短的例子來體驗一下這個過程:
int *addr; //用來儲存對映的位址
int shmid; //用來儲存共享記憶體的id識別符號
shmid = shmget(ipc_private, 4, 0); //獲得四個位元組大小的共享記憶體,返回的共享記憶體id識別符號被儲存到shmid中
addr = shmat(shmid, 0, 0); //對映共享記憶體,獲得共享記憶體位址
*addr = 3; //對共享記憶體進行操作,將這個位址賦值為3
shmdt(addr); //解除對映,但共享記憶體依然存在於系統中,沒有被刪除
shmctl(shmid, ipc_rmid, null); //刪除共享記憶體
上面只是乙個簡短示例,用來體會一下應用過程,實際編寫程式時,需要對返回值進行檢檢查,以免出錯。
檢視系統中已有的共享記憶體可用命令:ipcs
現在解釋一下這四個函式的用法:
1.int shmget(key_t key, int size, int shm***);
當key取值為ipc_private時,建立新的共享記憶體,大小由size決定。
當key取值不為ipc_private時,而且也不是已建立的共享記憶體ipc key,則視引數shm***中是否有ipc_creat標誌,來決定是否建立新的共享記憶體,並且以key值為新共享記憶體的ipc key。如果沒有ipc_creat標誌,則會返回錯誤。
當key取值為已建立的共享記憶體ipc key時,如果引數shm***中包含ipc_creat和ipc_excl,則返回錯誤。如果只包含這兩個標誌中的其中之一,或者兩個都不包含,則視size的大小是否小於等於這個已存在的共享記憶體的大小,如果小於等於,則返回這個共享記憶體的id識別符號;否則,返回錯誤。
引數shm***也可以用來設定共享記憶體的訪問許可權,其值相當於open()函式的mode用法,執行位不用。
返回值:若成功返回共享記憶體的id識別符號,錯誤返回-1,錯誤原因存於errno
2.void *shmat(int shmid, const void *shmaddr, int shm***);
shmid為共享記憶體id識別符號。
如果shmaddr為0,則由核心自動分配。
如果不為0,shm***也沒有指定ipc_rnd旗標,則以引數shmaddr為連線位址。
如果不為0,shm***指定了ipc_rnd旗標,則將自動將引數shm***調整為shmlba的整數倍。
shmlba的定義有兩種情況,如下:
#define shmlba page_size
#define shmlba (4 * page_size)
shm***還可以有shm_rdonly,表示對映的記憶體只可以讀。
2.在經過exec()之後,對映的位址連線會自動脫離。
3.程式執行結束之後,對映的位址連線也會自動脫離。
3. int shmdt(const void *shmaddr);
shmaddr為shmat()對映後獲得的位址,此函式解除shmaddr與它連線的共享記憶體之間的對映。
返回值:成功返回0,否則返回-1,錯誤原因存於errno
4. int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl()提供了幾種方式來控制共享記憶體的操作,shmid為共享記憶體的id識別符號,cmd為操作的命令,有如下操作:
ipc_stat 把共享記憶體的shmid_ds結構資料複製到buf(每個共享記憶體中,都包含有乙個shmid_ds結構,裡面儲存了一些關於本共享記憶體的資訊)
ipc_set 將引數所指的shmid_ds結構中的shm_perm.uid、shm_perm.gid和shm_perm.mode複製到共享記憶體的shmid_ds結構內。
ipc_rmid 刪除共享記憶體和其包含的資料結構
shm_lock 不讓此共享記憶體置換到 swap (什麼是swap,這個本人也不理解,如果有高手知道,希望不吝賜教)
shm_unlock 允許此共享記憶體置換到swap
shm_lock和shm_unlock為linux特有,且唯有超級使用者允許使用。
shmid_ds結構定義(linux-2.6.32.2):
struct shmid_ds ;
shm_segsz 共享記憶體的大小(bytes)。
shm_atime 最後一次attach(對映)此共享記憶體的時間
shm_dtime 最後一次detach(解除對映)此共享記憶體的時間
shm_ctime 最後一次更動此共享記憶體的時間。
shm_cpid 建立此共享記憶體的程序識別碼。
shm_lpid 最後乙個操作此共享記憶體的程序識別碼。
下面是乙個經典範例:
#include
#include
#include
#define key 1234
#define size 1024
int main()
else
} 後面是網上找的每個函式的詳解例子,前面是自己的實踐心得以及自己的解決方法,希望當你遇到共享記憶體的問題,這篇部落格記載對你有幫助
Linux程序間通訊 共享記憶體
共享記憶體是執行在同一臺機器上的程序間通訊最快的方式,因為資料不需要在不同的程序間複製。通常由乙個程序建立一塊共享記憶體區,其餘程序對這塊記憶體區進行讀寫。共享記憶體往往與其它通訊機制,如訊號量結合使用,來達到程序間的同步及互斥。首先要用的函式是shmget,它獲得乙個共享儲存識別符號。i nclu...
Linux程序間通訊 共享記憶體
之前提到了程序間通訊的管道,訊息佇列,訊號量,然後其中訊號量是pv操作,操控的是乙個共享資源。在我們提到的ipc模組中,訊息佇列針對的是資料單元的資訊傳送,管道不屬於system v ipc的部分,所以按照乙個作業系統的整體來說,他應該也有著乙個關於位元組流的訊息傳輸,並且要比之前都要快,還要跟我們...
Linux程序間通訊 共享記憶體
一 共享記憶體 1 共享記憶體的概念 顧名思義,共享記憶體就是允許兩個不相關的程序訪問同乙個邏輯記憶體。共享記憶體是在兩個正在執行的程序之間共享和傳遞資料的一種非常有效的方式。不同程序之間共享的記憶體通常安排為同一段物理記憶體。程序可以將同一段共享記憶體連線到它們自己的位址空間中,所有程序都可以訪問...