2014-01-08 26 views
4

我有一個多線程程序,主線程是第三方(無法更改它)和純C語言。我的任務是在它周圍建立新的模塊(使用C++),那些駐留部分在其他線程中,需要使用C程序的界面。基本上只是讀取一些在C線程中存儲和更新的變量(int,float,沒有什麼複雜的)。使用混合C和C++的線程同步

現在我的問題:我如何確保在訪問這些變量時不會因爲C界面而垃圾,因爲我無法在讀取時使用互斥鎖來鎖定它。這甚至有可能嗎?或者正在寫一個float/int原子操作呢?

+1

混合C/C++與問題無關。我建議調用這個線程「與外部庫的數據同步」或類似的東西。 – Dariusz

+0

什麼CPU和操作系統?我認爲這會影響到什麼是原子,什麼不是。另外,你總是會遇到緩存問題,也就是說其他線程已經改變了值,但是它還沒有寫入主RAM,所以你最好不要做任何有點過時的問題,這是一個致命的問題。 – hyde

+0

這就是我想的......我不想讓它依賴於某種特殊的架構。 – fewu

回答

0

你不能。讀寫任何東西都不是原子操作,如果你不能改變C代碼,那麼你運氣不好。同步化總是需要兩個部分被同步。

最好的辦法是要求第三方使他們的部分線程安全和/或與您共享鎖定機制。

+3

您通常可以在自己的調用代碼中執行所有鎖定 - 保護每個調用進入未知代碼,以便一次只有一個線程在C庫中。由於這有效地呈現單線程的C庫訪問,所以它幾乎可以保證工作。這種技術已經被用來與crufty本地圖書館進行交互,因爲,因爲有crufty本地圖書館。 – BeeOnRope

+0

我想這就是我要做的。要求第三方創建一個像他們每次更新值時調用的'WriteNewValue(int newVal)'的接口,以便我可以將該變量複製到我可以鎖定/解鎖訪問的C++世界中。 – fewu

3

你不能。在這種情況下工作的唯一正確方法是隻使用調用C線程提供給函數的參數 - 而不是之後存儲對它們的引用。沒有辦法保證任何變量不會被修改 - 一般情況下。

您需要重新考慮您的架構,以免出現這種需求。

1

如果您無法確定設置變量值的代碼是否同步,則在讀取時放置一個鎖是沒有意義的,並且不起作用。這不僅是操作的原子性,也是數據可見性 - 對這些變量的更新可能對其他線程不可見。

如果你控制主線程,你必須爲你必須訪問的每個人創建一個新變量,從主線程訪問它,並使用鎖定,設置新創建的變量的值。然後,從其他線程訪問只有那些同步變量。

int myVal = 0; 

int main() { 
    while(!shouldQuit()) { 
    doSomeIndependentStuff(); 
    pthread_lock(&mutex); 
    myVal = independentGlobalVal; 
    pthread_unlock(&mutex); 
    } 
} 

int getMyVal() { 
    int retVal = 0; 
    pthread_lock(&mutex); 
    retVal = myVal; 
    pthread_unlock(&mutex); 
    return retval; 
} 
5

語句如「寫入float/INT [是]一個原子操作反正」的,不幸的是,不能很好地在C或C++中定義(儘管與C++ 11和stdatomic使用std::atomic。 h的方法可以在這裏幫助 - 但這不會幫助你用C interop來創建一個你不能修改的庫,所以你可以在這裏忽略它)。

您可以在特定的編譯器和平臺上找到有關這些問題的指導 - 例如,您可能會發現在大多數平臺上,如果對齊,對齊的32位或64位讀取或寫入將是原子的,大多數編譯器會適當地調整它們。

但是,在這條路上走的是瘋狂。如果您涉及多個線程,只需使用POSIX/pthreads功能(如可從C和C++輕鬆訪問的pthreads mutexes)來防止跨線程共享狀態的任何訪問。

由於您無法修改C代碼,因此您可能必須在C++代碼中進行所有鎖定,然後才能調用C庫,然後解鎖。如果你可以閱讀,但不能修改C代碼,或者文檔對線程/共享模型非常清楚,你可以使用細粒度的鎖定策略,但是如果沒有任何分析表明存在瓶頸, d首先使用一個全局鎖來防止對C API的每次訪問。

+2

如果寫入不同步,鎖定只讀是毫無意義的。 – Dariusz

+2

c11也具有原子。 stdatomic.h – this

+2

我從來沒有建議鎖定只讀。我建議鎖定任何對C庫的調用,這將包含所有讀寫操作(由本地庫)。如果存在任何實際的共享狀態(例如共享庫公開的全局變量),則在訪問它時需要在C++端進行鎖定。 – BeeOnRope