[英](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;
}
請記住value
是spin->counta
的先前值,而后者已經增加了 1,我們期望spin->counta
等於value + 1
(除非在此期間發生了某些變化)。
因此,檢查是否spin->counta == SPINLOCK_SHARED | 1
spin->counta == SPINLOCK_SHARED | 1
( atomic_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 | 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.