1. 程式人生 > >(轉)Linux共享記憶體使用常見陷阱與分析(3)-ftok是否一定會產生唯一的key值

(轉)Linux共享記憶體使用常見陷阱與分析(3)-ftok是否一定會產生唯一的key值

轉自http://os.51cto.com/art/201311/418977_2.htm

ftok是否一定會產生唯一的key值?

系統建立IPC通訊(如訊息佇列、共享記憶體時)必須指定一個ID值。通常情況下,該id值通過ftok函式得到。

ftok原型如下:

  1. key_t ftok( char * pathname, int proj_id) 

pathname就時你指定的檔名,proj_id是子序號。

在一般的UNIX實現中,是將檔案的索引節點號取出,前面加上子序號得到key_t的返回值。如指定檔案的索引節點號為65538,換算成16進製為0×010002,而你指定的proj_id值為38,換算成16進製為0×26,則最後的key_t返回值為0×26010002。

查詢檔案索引節點號的方法是: ls -i

但當刪除重建檔案後,索引節點號由作業系統根據當時檔案系統的使用情況分配,因此與原來不同,所以得到的索引節點號也不同。

根據pathname指定的檔案(或目錄)名稱,以及proj_id引數指定的數字,ftok函式為IPC物件生成一個唯一性的鍵值。在實際應用中,很容易產生的一個理解是,在proj_id相同的情況下,只要檔案(或目錄)名稱不變,就可以確保ftok返回始終一致的鍵值。然而,這個理解並非完全正確,有可能給應用開發埋下很隱晦的陷阱。因為ftok的實現存在這樣的風險,即在訪問同一共享記憶體的多個程序先後呼叫ftok函式的時間段中,如果pathname指定的檔案(或目錄)被刪除且重新建立,則檔案系統會賦予這個同名檔案(或目錄)新的i節點資訊,於是這些程序所呼叫的ftok雖然都能正常返回,但得到的鍵值卻並不能保證相同。由此可能造成的後果是,原本這些程序意圖訪問一個相同的共享記憶體物件,然而由於它們各自得到的鍵值不同,實際上程序指向的共享記憶體不再一致;如果這些共享記憶體都得到建立,則在整個應用執行的過程中表面上不會報出任何錯誤,然而通過一個共享記憶體物件進行資料傳輸的目的將無法實現。

所以如果要確保key_t值不變, 要麼確保ftok的檔案不被刪除,要麼不用ftok,指定一個固定的key_t值。

如果存在生成key_t值的檔案被刪除過,則很有可能自己現在使用的共享記憶體key_t值會和另外一個程序的key_t值衝突,如下面這種情況:

程序1使用檔案1來ftok生成了key10000,程序2使用檔案2來ftok生成了key 11111,此時如果程序1和程序2都需要下載檔案,並將檔案的內容更新到共享記憶體,此時程序1和2都需要先下檔案,再刪掉之前的共享記憶體,再使用ftok生成新的key,再用這個key去申請新的共享記憶體來裝載新的問題,但是可能檔案2比較大,下載慢,而檔案1比較小,下載比較慢,由於檔案1和檔案2都被修改,此時檔案1所佔用的檔案節點號可能是檔案2之前所佔用的,此時如果下載的檔案1的ftok生成的key為11111的話,就會和此時還沒有是否11111這個key的程序2的共享記憶體衝突,導致出現問題。

解決方法:

方法一:

在有下載檔案操作的程式中,對下載的檔案使用ftok獲取key的時候,需要進行衝突避免的措施,如使用獨佔的方式獲取共享記憶體,如果不成功,則對key進行加一操作,再進行獲取共享記憶體,一直到不會產生衝突為止。

方法二:

下載檔案之前,將之前的檔案進行mv一下,先“佔”著這個檔案節點號,防止其他共享記憶體申請key的時候獲取到。

另外:

建立程序在通知其他程序掛接的時候,建議不使用ftok方式來獲取Key,而使用檔案或者程序間通訊的方式告知。