簡體   English   中英

在不使用volatile或內存屏障和鎖定的情況下保證執行順序

[英]Guaranteeing the order of execution without using volatile or memory barrier and locks

我有關於編譯器改變執行順序的問題。 我試圖通過用信號機制(thorugh信號量)替換臨界區來提高多線程程序(C語言)的性能。

我需要保證這里的執行順序,並且已經對此進行了一些研究。 我在函數中看到了許多關於執行順序的問題,但對函數中的函數沒有太多討論。

基於https://en.wikipedia.org/wiki/Sequence_point規則#4,將下面的代碼塊保證*p->a必須首先評估之前func2輸入自func2采用p作為輸入(假設編譯器遵守此處定義的調度點規則)?

func1 (struct *p) {
  p->a = x;  
  func2 (p);
}

func2 (struct *p) {
  p->b = y;
  releaseSemaphore(s);
}

至關重要的是, p->b僅在p->a被設置之后才被設置為另一個線程在處理各種請求的循環中並且通過是否設置p->b來識別有效請求。 釋放信號量只會在空閑(並等待信號量)時觸發任務,但如果它忙於處理其他請求,它將在稍后檢查p->b ,並且我們不能保證僅在該線程空閑時調用func1

否。序列點排序不會在線程邊界上轉換。 這就是為什么我們首先需要內存排序保證的原因。

對於執行代碼的線程,始終保證序列點排序(模數為if-if-rule)。 任何其他線程都可能以任意順序觀察該線程的寫入。 這意味着即使線程#1可以驗證它以特定順序執行寫入,線程#2仍可能以不同的順序觀察它們。 這就是為什么揮發性在這里還不夠。

從技術上講,這可以解釋為例如。 通過緩存。 線程#1的寫入可能首先進入寫緩沖區,它們仍然對線程#2不可見。 只有將寫入緩沖區刷回主存儲器后,它們才會變為可見,並且允許硬件在刷新之前對寫入進行重新排序。

請注意,僅僅因為允許平台重新排序寫入並不意味着它會。 這是危險的部分。 在一個平台上運行完美的代碼在移植到另一個平台時可能會突然出現。 使用適當的內存順序可確保代碼隨處可用

實施可以1改變順序,只要這不是沒有結束函數完成從其他翻譯單元調用。

這種重新排序與多線程正交,即它在單線程和多線程程序中完成。

如果函數func2與func1在同一個轉換單元中,則可以執行以下操作:

func1 (struct *p) 
{
    func2 (p);
    p->a = x;  
}

如果你想要防止2次這樣的重新排序,請使用volatile。 (請注意,這樣做是為了防止上面提到的重新排序,而不是出於其他同步目的。您將不得不使用原子基元。)


1 (引用自:ISO / IEC 9899:201x 5.1.2.3程序執行10)
或者,實現可以在每個轉換單元內執行各種優化,使得實際語義僅在跨轉換單元邊界進行函數調用時才符合抽象語義。

2 (引用自:ISO / IEC 9899:201x 6.7.3類型限定符7)
具有volatile限定類型的對象可能以實現未知的方式進行修改,或者具有其他未知的副作用。 因此,任何涉及這種對象的表達都應嚴格按照抽象機的規則進行評估,如5.1.2.3所述。 此外,在每個序列點,最后存儲在對象中的值應與抽象機器規定的值一致,除非由前面提到的未知因素修改。

暫無
暫無

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

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