簡體   English   中英

Linux上C ++中線程/共享內存之間的線程安全數據交換

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM