0

我想使用一个通常计数为 2^40 的原子计数器(多线程计算),所以我不能直接使用 32 位 int 原子计数器。我还没有 c++11(我将迁移到它,但还没有,因为这对我来说是有成本的),我必须在 32 位和 64 位平台上编译。我目前使用 QT,所以我可以使用 QAtomicInt。

这是我的想法:

(initialization...)
QAtomicInt counterLo = 0;
QAtomicInt counterHi = 0;


void increment()
{
    int before = counterLo.fetchAndAddOrdered(1);
    if(before==INT_MAX)
    {
        counterHi.fetchAndAddOrdered(1); //Increment high word
        counterLo.fetchAndAddOrdered(INT_MAX);    //Increments low word to -1
        counterLo.fetchAndAddOrdered(1);   //Increments low word to 0
    }         
}

uint64_t value()
{
    //Wait until the low word is non-negative
    int lo = counterLow;
    while(lo<0)
        lo = counterLow;

    return (uint64_t)counterHi * ((uint64_t)INT_MAX+1) + (uint64_t)lo;
}

这个对吗?我已经尝试使用互斥锁来制作计数器,但性能下降了大约 10%。这被称为每秒大约 100 万次,在 8 个线程之间共享(蒙特卡罗模拟的样本计数器)

谢谢!

4

2 回答 2

1

这不是整体原子的,请参见以下示例:

  • hi=0,lo=INT_MAX
  • T1调用value(),获取lo=INT_MAX,被中断
  • T2 调用将increment()hi 增加到 1
  • T1恢复读取counterHi,得到1,返回值2^32 + INT_MAX

这可能不是您想要的。难道你不能只分割你的样本空间,让每个线程计算 n/8 个项目而不争夺锁吗?

于 2013-03-19T11:17:50.053 回答
1

当然,这不是原子的。原子操作的序列可以被中断。我建议使用保护(互斥锁或临界区)。

于 2013-03-19T11:25:47.610 回答