繁体   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