簡體   English   中英

指針解除引用原子?

[英]Is pointer dereferencing atomic?

假設我有一個指向整數的指針。

volatile int* commonPointer = new int();

我有多個線程可以取消引用該指針。

int blah = *commonPointer;

但是,一個線程需要更改指針的地址:

int* temp = new int();
int* old = commonPointer;
InterlockedExchange(&commonPointer,temp);
delete old;

現在,讓我們忽略一些線程可能正在讀取“舊”值的事實,而有些線程可能正在讀取“新”值,這在我的情況下不是問題。

是否存在一個線程開始取消引用指針的情況,就像刪除地址一樣,然后獲得異常?
或者解除引用足夠的原子以便不會發生?

在這種情況下,C ++標准中沒有任何內容可以保證原子性。

您必須使用互斥鎖保護相關代碼區域:即使std::atomic還不夠,因為它只提供對指針的原子訪問,但不包括取消引用操作。

也許,C ++ 11

atomic<shared_ptr<int> > 

滿足您的需求。 它會阻止舊值消失,直到至少有一個對該值的引用有效。

atomic<shared_ptr<int> >  commonPointer;

// producer:
{
    shared_ptr<int> temp(new int);
    shared_ptr<int> old= atomic_exchange(&commonPointer, temp); 
    //...
};// destructor of "old" decrements reference counter for the old value


// reader:
{
    shared_ptr<int> current= atomic_load(&commonPointer);

    // the referent pointed by current will not be deleted 
    // until   current is alive (not destructed);
}

但是,原子共享ptr的無鎖實現很復雜,因此可能會在庫實現中使用鎖或自旋鎖(即使您的平台上有可用的實現)。

首先,聲明中的volatile不會產生任何實際影響。 其次,只要在一個線程中修改一個值並在多個線程中訪問它,就必須保護所有訪問。 否則,您有未定義的行為。 我不知道InterlockedExchange給出了什么保證,但我確信它對任何不調用它的線程都沒有影響。

編輯2:對不起,不,它沒有幫助。 你需要在訪問周圍使用互斥鎖 - 編譯器生成的代碼很可能(非常可能)將指針加載到寄存器[或其他存儲器,例如堆棧,如果它是沒有寄存器的處理器],然后訪問存儲器指針指向at,同時,指針正被另一個線程更新。 保證指針正確的唯一方法是使用互斥鎖或類似結構來關閉整個訪問塊。 任何其他事情都可能失敗。

正如syam所說,標准並不保證即使讀取指針所指向的32位值也是原子的 - 它依賴於系統的實現。 但是,如果你問“我會得到一個值是舊值還是新值”,那么至少x86和x86-64將保證這一點。 其他機器架構可能沒有(SMP 68000處理器上的32位int實現不能保證它,因為一次寫入是16位,而第二個處理器可能寫了一半,但不是另一個 - 不是我知道有一個68MP處理器的SMP系統正在構建中。

InterlockedExchange (不是“標准”函數)將保證該線程的處理器具有對指針本身的EXCLUSIVE訪問權限,因此可以安全地執行 - 此時沒有其他處理器能夠訪問指針。 這是x86架構中“鎖定”指令的重點 - 它們是“安全的”(而且相當慢,但假設你不是每次都這樣做......)。

編輯:請注意,您必須小心使用commonPointer本身,因為編譯器可能沒有意識到您正在使用另一個線程來更新它。 所以你可能仍然在讀取OLD指針值。

調用函數[沒有內聯到虛無]或聲明指針volatile int * volatile commonPointer; 應該做的伎倆。 [提示人們使用volatile回應我的答案,因為“沒有問題,解決方案就像之前發布的人一樣volatile ”。

[見上面的edit2]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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