我想实现以下支持以下操作的原子对象:
inc_and_get(X) - increment the counter and return the previous value
dec(X) - decrement the counter
inc_and_disable_if_zero (x) - increment the counter, but if the value is zero, disable it
disable means it returns -1 for every operation
inc_and_get(X)和dec(X)可以使用基本硬件原语实现
我感兴趣的是:inc_and_disable_if_zero
增量对应于进入临界区并减少到离开。
进入关键部分的线程可以决定定期输入(通过执行inc_and_get)或尝试通过调用inc_and_disable_if_zero
来输入和禁用计数器(如果可能的话)(没有其他人在那里)我认为可以用CAS(X)来解决这个问题:
inc_and_disable_if_zero(X)
do {
value = READ(X)
if (value == 0) {
next_value = -1;
disable = TRUE;
} else if (value > 0) {
next_value = value + 1; // no good, :( , just increment
disable = FALSE;
} else {
return (TRUE); // someone else disabled it
}
} while (!CAS(value, next_value));
return (disable);
但我想知道是否有更优雅的方法来解决这个问题(使用单一的原子 操作)?
例如,如果计数器为零,则递增并设置MSB?
答案 0 :(得分:0)
JFYI:CAS有三个参数,指向原子变量,旧值和新值。
您可以使用双重检查锁定(在自旋锁上)解决此问题:
int inc_and_disable_if_zero(Counter* X) {
// fast path
if (X->value == -1) {
return -1;
}
lock(X->spinlock);
if (X->value == -1) {
unlock(X->spinlock);
return -1;
}
if (X->value == 0) {
X->value = -1;
unlock(X->spinlock);
return -1;
}
X->value++;
int res = X->value;
unlock(X->spinlock);
return res;
}
在这种情况下,必须在spinlock下执行对计数器的所有更新。
int inc(Counter* X) {
// fast path
if (X->value == -1) { return -1; } // this value couldn't change so
// there is no need for synchronization
lock(X->spinlock);
if (X->value == -1) { return -1; }
X->value++;
int res = X->value;
unlock(X->spinlock);
return res;
}
在这种情况下性能会很好,自旋锁定/解锁只是一个RMW操作,与CAS相同。
例如,如果计数器为零,则递增并设置MSB?
我认为现代英特尔' Haswell'使用TSX(事务同步扩展)的处理器。我相信,通过常规CAS操作,这是不可能的。