1

在互聯網之間進行通信,可以找到關於並行編程使用volatile關鍵字的許多爭論,有時相互矛盾的論證。使用標誌線

一本主題更值得信賴的討論似乎是this article by Arch Robison。他使用的例子是從一個線程傳遞一個值到另一個任務:

主題1.計算矩陣乘積,並賦予其主題2,這確實其他的東西吧。該矩陣是可變的M並且該標誌是volatile指針R

  1. 線程1相乘計算一積矩陣M和原子設置 R鍵指向M.
  2. 線程2個等待,直到ř!= NULL,然後使用中號,以計算另一矩陣乘積的一個因素。

換句話說,M是一個消息,並且R是就緒標誌。

作者聲稱,雖然將R聲明爲volatile將解決將線程1中的變化傳播到線程2的問題,但不會保證M發生這種情況時的值。並且可以對RM的分配進行重新排序。所以我們需要使MR不穩定,或者在像pthreads這樣的庫中使用一些同步機制。

我的問題是,如何做到用C

1)以下如何共享兩個線程之間的一個標誌 - 如何原子分配給它,確保其他線程將看到變化和測試在另一個線程中的變化。在這種情況下使用易變的合法嗎?或者一些圖書館可以提供一個概念上更好或更快的方式,可能涉及記憶障礙?

2)如何做羅賓遜的例子吧,所以如何從一個線程安全地並行線程發送矩陣M到其他並做到這一點(最好是可移植的)

回答

0

「揮發性」是爲一個提示編譯器不會優化內存訪問,也就是說,不要認爲自上次(本地)寫入以來內存中的值不變。如果沒有這個提示,編譯器可能會認爲寄存器的值(從變量複製而來)仍然有效。 因此,雖然矩陣不太可能保存在寄存器中,但通常這兩個變量對於接收器而言應該是易變的或更精確的。

在現實生活中的多線程,一個寧願用旗語或類似的信號,避免了接收器忙等待。

+0

爲了迴應你第一個問題中的最後一句話,安迪羅賓遜說這兩個變量對於*兩邊都應該是易變的,因爲易變也會阻止賦值語句和矩陣的重新排序。但我認爲你爲了簡單而將這個重新排序的問題拋出去了。 – user7610 2012-02-28 12:54:09

+0

一個矩陣,特別是在一個多線程應用程序中,它預計在線程之間進行通信,可能會動態分配並通過其指針進行訪問。指針通常是寄存器大小:( – 2012-02-28 13:01:22

+0

)如果發送方重新使用矩陣或指針,則只需在發送方有一個volatile。重新排序是一個獨立的問題,因爲Necrolis聲明,在C11中,您可以使用_Atomic。 – Matthias 2012-02-28 13:11:56

1

在像x86這樣的體系結構下,像指針這樣正確對齊(和大小)的變量將默認從原子地讀取和寫入,但需要發生的是內存讀/寫的串行化以防止在CPU中重新排序流水線(通過使用明確的內存圍欄或總線鎖定操作)以及使用volatile來防止編譯器對其生成的代碼重新排序。

最簡單的方法是使用CAS。大多數CAS內部函數在編譯器和CPU內存總線級別提供完整的內存屏障。在MSVC下,您可以使用Interlock*函數,BTS,BTR,Inc,Dec,Exchange和Add都可以用於標誌,對於GCC,您可以使用基於__sync_*的變體。

對於更便攜的選項,您可以使用pthread_mutexpthread_cond。如果您可以使用C11,則還可以查看_Atomic關鍵字。

0

「經典」方式是讓線程1將指針指向動態分配的矩陣,並將其傳遞到線程2正在等待的生產者 - 消費者隊列中。一旦推送,線程1可以分配另一個M並開始處理它,如果它願意的話。

如果整體性能受大矩陣運算的支配,擺弄易失性標誌等作爲優化可能爲時過早。