原子计数器,当达到0时可以被禁用

时间:2014-07-28 08:29:45

标签: c multithreading concurrency atomicity

我想实现以下支持以下操作的原子对象:

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?

1 个答案:

答案 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操作,这是不可能的。