[英]thread safe data exchange between threads/shared memory in C++ on linux
我對此感到困惑:在生產過程中,我們有兩個進程通過共享內存進行通信,數據交換的一部分是漫長的,而且是一個bool。 對此數據的訪問不同步。 它已經很好地工作了很長時間,現在仍然如此。 我知道修改一個值不是原子的,但考慮到這些值被修改/訪問數百萬次,這不得不失敗?
這是一段代碼示例,它在兩個線程之間交換一個數字:
#include <pthread.h>
#include <xmmintrin.h>
typedef unsigned long long uint64;
const uint64 ITERATIONS = 500LL * 1000LL * 1000LL;
//volatile uint64 s1 = 0;
//volatile uint64 s2 = 0;
uint64 s1 = 0;
uint64 s2 = 0;
void* run(void*)
{
register uint64 value = s2;
while (true)
{
while (value == s1)
{
_mm_pause();// busy spin
}
//value = __sync_add_and_fetch(&s2, 1);
value = ++s2;
}
}
int main (int argc, char *argv[])
{
pthread_t threads[1];
pthread_create(&threads[0], NULL, run, NULL);
register uint64 value = s1;
while (s1 < ITERATIONS)
{
while (s2 != value)
{
_mm_pause();// busy spin
}
//value = __sync_add_and_fetch(&s1, 1);
value = ++s1;
}
}
正如你所看到的,我已經評論了幾件事情:
// volatile uint64 s1 = 0;
和
// value = __sync_add_and_fetch(&s1,1);
__sync_add_and_fetch以原子方式遞增變量。
我知道這不是很科學,但運行幾次沒有同步功能它完全沒問題。 此外,如果我測量兩個版本的同步和沒有同步,它們以相同的速度運行,為什么__sync_add_and_fetch沒有添加任何開銷?
我的猜測是編譯器保證了這些操作的原子性,因此我沒有看到生產中的問題。 但仍無法解釋為什么__sync_add_and_fetch不會增加任何開銷(甚至在調試中運行)。
關於礦山環境的更多細節:ubuntu 10.04,gcc4.4.3 intel i5 multicore cpu。
生產環境類似於它在更強大的CPU和Centos OS上運行。
謝謝你的幫助
基本上你在問“為什么我之間的行為/表現沒有區別
s2++;
和
__sync_add_and_fetch(&s2, 1);
那么,如果你去看看這兩種情況下編譯器生成的實際代碼,你會發現存在差異 - s2++
版本將有一個簡單的INC指令(或可能是ADD),而__sync
版本將在該指令上有一個LOCK前綴。
那么為什么沒有LOCK前綴呢? 好吧,雖然通常情況下需要LOCK前綴才能在任何基於x86的系統上運行,但事實證明它不需要它。 使用基於Intel Core的芯片,LOCK僅需要通過總線在不同CPU之間進行同步。 在單個CPU(即使有多個內核)上運行時,它會在沒有它的情況下進行內部同步。
那你為什么看不到__sync
案例的減速? 那么,Core i7是一個“有限”的芯片,因為它只支持單插槽系統,所以你不能擁有多個CPU。 這意味着永遠不需要LOCK,事實上CPU完全忽略了它。 現在代碼大1個字節,這意味着如果ifetch或decode有限,它會產生影響,但你不是,所以你看不出任何區別。
如果您要在多插槽Xeon系統上運行,您會看到LOCK前綴的(小)減速,並且還可以在非LOCK版本中看到(罕見)故障。
我認為編譯器在使用某些特定於編譯器的模式之前不會產生原子性,所以這是不行的。
如果只有兩個進程正在使用共享內存,通常不會出現任何問題,特別是如果代碼片段足夠短。 操作系統更喜歡阻塞一個進程並在其最佳時運行另一個進程(例如I / O),因此它將運行一個到一個良好的隔離點,然后切換到下一個進程。
嘗試運行相同應用程序的幾個實例,看看會發生什么。
我看到你正在使用Martin Thompson的線程間延遲示例。
我的猜測是編譯器保證了這些操作的原子性,因此我沒有看到生產中的問題。 但仍無法解釋為什么__sync_add_and_fetch不會增加任何開銷(甚至在調試中運行)。
編譯器不保證這里的任何內容。 你正在運行的X86平台是。 這段代碼可能會在時髦的硬件上失敗。
不確定你在做什么,但C ++ 11確實提供了std :: atomic的原子性。 你也可以看一下boost :: atomic 。 我假設你對Disruptor模式感興趣,我會無恥地將我的端口插入C ++,稱為disruptor-- 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.