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