2013-08-23 14 views
3

我讀程序使用POSIX線程(由大衛Butenhof),他利用並行線程庫中提到:無論是直接或等待一個通過pthread庫的內存可視性?

無論內存值線程可以看到,當解鎖一個互斥體, 條件變量,也可以是任何線程看到的後續鎖定相同的互斥鎖的 。同樣,鎖定互斥鎖後寫入的數據 可能不一定會被鎖定互斥鎖的線程看到,即使寫入發生在鎖定之前。

突然,我不知道下面的代碼是否有效:

線程A:

strcpy(buffer, "hello world"); 
pthread_spin_lock(&lock); // assuming the mutex in the statement above can be interchanged with spinlock. I don't see why it can't 
pthread_spin_unlock(&lock); 

線程B:

pthread_spin_lock(&lock); 
pthread_spin_unlock(&lock); 
// read buffer; assuming thread B has a copy of the pointer somehow 

我的問題是:線程B在緩衝區中看到「hello world」?根據他的說法,它應該。我明白「通常」的做法是通過鎖定來保護共享的「資源」。但假設strcpy()發生在隨機時間,並且它只能在程序生命週期中發生一次,並假設線程B以某種方式在線程A調用pthread_spin_unlock()後調用pthread_spin_lock():

Side question :是否有更快的方式使更改緩衝對其他線程可見?假設可移植性不是問題,我在CentOS上。我能想到的另一種方法是使用mmap(),但不確定是否有任何更改是全局可見的,而不使用pthread庫。

+1

我認爲mmap()的概念是可行的,因爲它允許不同的進程看到相同的內存,更不用說線程了。 – Jiminion

+0

@Jim謝謝你的回覆。嗯... mmap()可能適用於MAP_SHARED。不知道是否有更快的方式。 – Hei

回答

1

我不認爲你已經正確地理解這一點:鎖不神奇地傳送數據,它們是線程之間的通信方式,它可以安全地移動數據。

在你的問題中,你做了很多假設。事實上,如果鎖不存在,只要你的假設都成立,你寫的所有東西都是同樣的。併發編程的問題是,一般來說,你不能假設那樣的

如果線程A進行了更改存儲器那麼變得可見到線程B 即刻(允許緩存和編譯器優化的反覆無常)。無論有沒有鎖,這總是如此。但是,如果沒有鎖,就不能保證寫入完成,甚至開始。

你擁有的報價第一假設(需要),你只寫共享數據和鎖定設置。最後一部分告訴你,如果你嘗試寫入而不先鎖定,會發生什麼壞事。

我不知道什麼是「即使發生前寫鎖」的意思,確切的說,但它可能是指各種各樣的競爭條件和困擾併發程序內存緩存的效果。這些鎖實際上可能不會傳輸數據,但它們會被編碼,以致它們強制編譯器在整個調用中同步內存(「內存障礙」)。

+0

我知道我不能做出任何假設,但只能基於pthread(或其他線程庫)的代碼保證。我的帖子試圖幫助我更好地理解保證。 – Hei

+0

爲什麼我可以保證在線程B的讀取之前線程A完成的寫操作是線程B不會嘗試讀取,直到線程A向線程B發信號通知線程B這樣做。但是,當我說「信號」時,我並不是指pthread_cond_signal或任何涉及內存障礙的信號。信號可以通過管道,tcp插座等完成(是的,聽起來很愚蠢......但我有我自己的理由)。 – Hei

+0

是的,有許多方法可以做信號,但是你需要一些內存屏障來確保內存的一致性。幸運的是,調用外部函數通常足以做到這一點,所以它自然發生。如果沒有屏障,編譯器可以自由保存您認爲寫入寄存器內存的數據,或重新排列它認爲不相關的表達式。事實上,只要你無法從外部知道,編譯器就可以完全重寫你的整個程序;不幸的是,如果你不採取一些預防措施,可以打破線程。 – ams