2012-03-02 115 views
1

當我動態加載共享庫時(例如在Linux上使用dlopen)時,是否必須擔心處理器之間加載庫的可見性,還是會自動圍欄/確保安全?共享庫(dlopen)和庫靜態指針的線程安全性

例如,說我有在裝載的庫此功能:

char const * get_string() 
{ return "literal"; } 

在使用這樣的字串文本指針主程序是多個線程之間的安全,因爲他們都保證看到它的初始值。然而,我想知道「初始值」的規則是如何真正適用於已加載的庫(因爲標準並沒有太多處理它)。

說我加載庫,然後立即調用get_string函數。我通過非內存排序原子將指針傳遞給另一個線程(在C++ 11中用寬鬆的說法)。另一個線程可以安全地使用這個指針而不必發出任何載入柵欄或其他同步指令嗎?

我的假設這是安全的,也許是因爲新的庫會被加載到新的頁面中,另一個核心不能讓它們加載,因此不能在它們上面具有舊的可見性?

如果可能的話,我希望有某種授權參考作爲答案的一部分。或者是關於如何在默認情況下使其成爲線程安全的技術說明。或者,如果它本身不是線程安全的,那當然是一種駁斥。

+0

@DeadMG,這仍然是C/C++相關的。我使用C字符串文字結構,因爲它具有特定的生命期限。此外,特定的語言編譯器/鏈接器肯定涉及解決這個問題,從這個角度來看,我對C或C++語言工具鏈感興趣。 – 2012-03-02 17:43:16

+2

它比任何其他本地代碼庫中的任何其他靜態數據都沒有更多的終身保證。而語言編譯器/鏈接器沒有關於'dlopen'的說法 - 它是一種操作系統函數,它在每個本地代碼庫上都是相同的,而不考慮源語言。呵呵,C和C++是完全不同的語言,在你提出這個問題之前,你是否想要一個或另一個是非常重要的事情。 – Puppy 2012-03-02 20:16:10

+0

'dlopen'當然不是OS功能,而是Linux上glibc的一部分。 dlopen的結果只能用於支持原始指針訪問的語言,因此主要是C和C++。 – 2012-03-04 08:16:16

回答

1

我會擴展Basile說的。我跟進了glibc,發現了dlopen使用mmap的行爲。內存可視性的所有保證都是從mmap系統調用中假定的,dlopen本身不作任何額外的保證。

mmap的用戶通常假設它會在所有處理器的返回點正確映射內存,這樣可見性就不成問題了。這似乎並不是一個明確的保證,但如果沒有這種保證,操作系統可能無法使用。也沒有已知的系統,在這種情況下不能按預期工作。

1

你的問題是:將dlopen()正確加載我的lib代碼之前返回?是的,它會。 否則,你會遇到只有一個線程的問題。如果你不得不在dlopen異步完成之前睡眠,那將是非常困難的。它還將執行各種檢查並初始化之前您有機會獲得您正在尋找的函數指針。這意味着如果你得到這個指針,一切都在這裏,你可以直接在任何線程中使用。

現在當然,你需要將這個指針與通常的線程安全性一起傳遞,但我假設你知道如何。

請注意,靜態初始化和模塊不能很好地協同工作(查看關於該主題的所有其他問題)。

你對核心的評論很奇怪。內核不加載內存。他們在緩存中預取它,但這不是問題,只是有點慢。

+0

不,我特別關注其他處理器的可見性。 – 2012-03-02 16:17:43

+0

由於'mmap'正在修改進程內所有線程的地址空間(根據「進程」的定義),並且由於內核具有硬件輔助的緩存一致性,所以它對其他內核(運行同一進程的其他線程)可見。 http://en.wikipedia.org/wiki/Cache_coherence – 2012-03-02 17:36:40

+1

@Basile,我理解緩存一致性,但是dlopen保證使用mmap,並且保證不重用現有的地址空間嗎?另外,CPU在加載期間不會鎖定其他線程(或者是否會?),所以我不清楚其他線程將如何被迫同步。再次,我明白它最有可能是安全的,我只是在尋找說明這個(我討厭假設任何東西)的規格/文檔 – 2012-03-02 17:47:59