簡體   English   中英

(x | y) - y 為什么不能簡單地是 x 甚至是 `x | 0`

[英](x | y) - y why can't it simply be x or even `x | 0`

我正在閱讀內核代碼,並且在一個地方我看到了if語句中的一個表達式,例如

if (value == (SPINLOCK_SHARED | 1) - 1) {
         ............
}

其中SPINLOCK_SHARED = 0x80000000是預定義的常量。

我想知道為什么我們需要(SPINLOCK_SHARED | 1) - 1 - 用於類型轉換目的? 表達式的結果將是 80000000-- 與 0x80000000 相同,不是嗎? 然而,為什么 ORing 1 和 Subtracting 1 很重要?

有一種感覺,我想得到一些東西..

代碼位於_spin_lock_contested ,當其他人試圖獲取鎖時,它會從_spin_lock_quick調用:

count = atomic_fetchadd_int(&spin->counta, 1);
if (__predict_false(count != 0)) {
    _spin_lock_contested(spin, ident, count);
}

如果沒有比賽,那么count (前一個值)應該是0 ,但它不是。 count數值作為參數傳遞給_spin_lock_contested作為value參數。 然后使用來自 OP 的if檢查該value

/*
 * WARNING! Caller has already incremented the lock.  We must
 *      increment the count value (from the inline's fetch-add)
 *      to match.
 *
 * Handle the degenerate case where the spinlock is flagged SHARED
 * with only our reference.  We can convert it to EXCLUSIVE.
 */
if (value == (SPINLOCK_SHARED | 1) - 1) {
    if (atomic_cmpset_int(&spin->counta, SPINLOCK_SHARED | 1, 1))
        return;
}

請記住valuespin->counta的先前值,而后者已經增加了 1,我們期望spin->counta等於value + 1 (除非在此期間發生了某些變化)。

因此,檢查是否spin->counta == SPINLOCK_SHARED | 1 spin->counta == SPINLOCK_SHARED | 1atomic_cmpset_int的前提)對應於檢查value + 1 == SPINLOCK_SHARED | 1 value + 1 == SPINLOCK_SHARED | 1 ,可以重寫為value == (SPINLOCK_SHARED | 1) - 1 (同樣,如果在此期間沒有任何變化)。

雖然value == (SPINLOCK_SHARED | 1) - 1可以重寫為value == SPINLOCK_SHARED ,但它保持原樣,以闡明比較的意圖(即將增加的先前值與測試值進行比較)。

或者哦。 答案似乎是:為了清晰和代碼一致性。

我認為目標可能是忽略最低有效位:

  • 如果用二進制表示的 SPINLOCK_SHARED 是 xxx0 -> 結果是 xxx0
  • 如果 SPINLOCK_SHARED = xxx1 -> 結果也是 xxx0

使用位掩碼表達式也許會更清楚?

的效果

(SPINLOCK_SHARED | 1) - 1

是為了確保在與value比較之前清除結果的低位。 我同意這似乎毫無意義,但顯然低階位具有特定用法或含義,在此代碼中並不明顯,我認為我們必須假設開發人員有充分的理由這樣做。 一個有趣的問題是 - 您正在查看的整個代碼庫中是否使用了相同的模式( | 1) -1 )?

這是一種編寫位掩碼的混淆方式。 可讀版本: value == (SPINLOCK_SHARED & ~1u)

這樣做只是為了清楚起見,僅此而已。 這是因為 atomic_fetchadd_int()(例如在 sys/spinlock2.h 中)返回加法/減法之前的值,並將該值傳遞給 _spin_lock_contested()

請注意,C 編譯器會完全預先計算所有常量表達式。 事實上,編譯器甚至可以根據使用傳入過程參數的條件來優化內聯代碼,當過程在這些參數中傳遞常量時。 這就是為什么 sys/lock.h 中的內聯 lockmgr() 有一個 case 語句......因為整個 case 語句將被優化並轉化為對適當函數的直接調用。

此外,在所有這些鎖定函數中,原子操作的開銷使所有其他計算相形見絀兩個或三個數量級。

-馬特

最喜歡這樣做是為了處理幾個額外的情況。 例如,在這種情況下,我們說SPINLOCK_SHARED不能為 1:

int SPINLOCK_SHARED = 0x01

int res = (SPINLOCK_SHARED | 1) - 1 // 0

暫無
暫無

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

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