轉的]dll的多進程多線程安全的幾種策略
[from:http://www.cnblogs.com/moonz-wu/archive/2008/05/08/1189021.html] 1、動態庫只有一個導出函數。 這種情況非常少,也是最容易處理的情況。這種情況下編寫函數時,只需要考慮不要有衝突的全局數據就可以了。這裏的全局數據包括了在堆中分配的數據塊和靜態全局變量等。如果存在這樣的全局數據,那麼進程中的不同線程訪問這個函數就會造成衝突。 解決辦法也很簡單,就是儘量用堆棧(stack)來解決問題。由於堆棧的所有人是線程,所以它必然是線程安全的。當然也要注意避免堆棧溢出。 我們都知道,如果要在函數再次調用時保留前一次調用的狀態,可以使用靜態變量。但如果你要保持函數的線程安全,那麼靜態變量是不能用的,因爲靜態變量是全局的,是屬於進程的,也就是屬於進程內線程共享的。所以如果確實需要在同一線程中保持函數的狀態,相當於在不同次調用間傳遞參數,可以考慮使用靜態全局線程局部變量,即: 2、動態庫導出了多個函數,而且多個函數間存在數據傳遞。 就像前面說的,一般DLL都導出多個函數,一個初始化,一個資源釋放,其他爲核心功能函數。這些函數間極有可能發生數據傳遞。如果一個初始化函數是在線程A中調用的,而核心功能函數是在線程B中調用的,那麼線程A初始化函數的資源就無法對應線程B中的核心功能,此外還有核心功能函數間的數據傳遞,這樣的DLL就不是線程安全的,必然導致錯誤。 解決辦法是由用戶(即使用DLL的人)保證這些導出函數是在一個線程中調用。但這樣會很大程度上限制接口的設計和用戶的使用自由度。所以最好的方法是函數只管自己的線程安全,不同函數傳遞數據用動態TLS,線程局部存儲。 比如: 這樣,只要DLL中每個函數保證其局部是線程安全的,函數間傳遞數據通過TLS(靜態和動態),就可以實現整個DLL的線程安全。 3、限制訪問DLL中某一函數的線程數目。 有時候,對於DLL中的某一個函數的訪問線程數目是有限制的,超過了限制其他線程就得等一定的時間,一定的時間過後如果還不能得到執行機會,那就返回超時。這樣的設計對用戶來說是友好的,而且很實用,有的商業程序確實是按照允許用戶訪問的通道數目來計價的。 對DLL中的函數做這樣的一個封裝,一般是簡單的待用Semaphore信號量,來解決。DLL初始化時調用CreateSemaphore函數對信號量進行初始化,其原型如下: 4、多進程情況下的多線程安全DLL。 前面3講了有時候需要對某一函數的訪問線程進行限制,而我們知道,DLL是可以被多個進行加載並調用的。那就是說如果我們只對一個進程進行了限制,那麼在多進程調用的情況下,這樣的限制被輕易攻破。 我們都知道,Semaphore信號量屬於內核對象,也就是說其可以被多進程共享訪問,也就說,如果我們給一個Semaphore指定了一個名字,在另一個進程中,我們只要調用OpenSemaphore函數用同一名字打開信號量就可以訪問了。這樣問題就解決了? 現實情況是,多進程情況下,一般不是簡單的多進程共享一個Semaphore就可以了。多進程間需要互通很多信息。一般的解決辦法是,採用共享數據段。 |