C++ c++;11 0时uint64_t循环的原子减量

C++ c++;11 0时uint64_t循环的原子减量,c++,multithreading,c++11,atomic,decrement,C++,Multithreading,C++11,Atomic,Decrement,我正在尝试编写一个简单的并行处理系统,该系统将生成N个对象,并将其放入多线程环境中的容器中 为了告诉线程何时停止生成对象,我创建了一个简单的反向计数器,从N开始,从run down开始,从0开始,每个线程并行递减。 计数器应该是uint64_t,我想尝试C++11的原子支持。代码如下所示 //Class member std::atomic<uint_fast64_t> counter //Parallel function while(counter-- > 0) { do

我正在尝试编写一个简单的并行处理系统,该系统将生成N个对象,并将其放入多线程环境中的容器中

为了告诉线程何时停止生成对象,我创建了一个简单的反向计数器,从N开始,从run down开始,从0开始,每个线程并行递减。 计数器应该是uint64_t,我想尝试C++11的原子支持。代码如下所示

//Class member
std::atomic<uint_fast64_t> counter

//Parallel function
while(counter-- > 0)
{
do something
}

原子性只保证所有线程都能看到一致的
原子值。通常,像
--
这样的操作是读-修改-写操作。原子
只保证在另一个线程忙于修改计数器时,没有其他线程修改计数器

要澄清:
原子的
防止数据竞争,没有别的

假设两个线程T1和T2以及以下R、M、W序列:现在线程T2的结果已被T1的结果覆盖,即计数器的值不一致

T1:读取T2:读取T2:修改T1:修改T2:写入T1:写入


因此,在您的问题中,代码执行
计数器--
,这意味着
--
将始终执行,而不管其值是多少。因此,如果该值已经为零,那么它现在将是-1,或者在使用
无符号
数据类型时,
无符号
类型的最大值。

原子性只保证所有线程都能看到一致的
原子
值。通常,像
--
这样的操作是读-修改-写操作。原子只保证在另一个线程忙于修改计数器时,没有其他线程修改计数器

要澄清:
原子的
防止数据竞争,没有别的

假设两个线程T1和T2以及以下R、M、W序列:现在线程T2的结果已被T1的结果覆盖,即计数器的值不一致

T1:读取T2:读取T2:修改T1:修改T2:写入T1:写入

因此,在您的问题中,代码执行
计数器--
,这意味着
--
将始终执行,而不管其值是多少。因此,如果该值已经为零,那么它现在将为-1,或者在使用
无符号
数据类型时,
无符号
类型的最大值。

您的假设 这或多或少是正确的
(无符号)0-1将是最大的无符号整数。你的原子减量总是会发生,即使条件是假的

我们如何解决这个问题? 我相信你实际上在寻找这样的东西:

std::atomic<uint_fast64_t> counter;
while (true) {
    uint_fast64_t cur = counter;
    if (cur == 0)
        break;
    if (counter.compare_exchange_strong(cur, cur - 1) == false)
        continue;

    ... // Perform work
} 
std::原子计数器;
while(true){
uint\u fast64\u t cur=计数器;
如果(cur==0)
打破
if(计数器比较交换强(cur,cur-1)=false)
持续
…//执行工作
} 
首先,我们测试计数器的当前值是否为0。如果是的话,我们工作完了,我们应该辞职

如果它大于0,那么我们需要减小计数器。这是一个比较和交换操作。因此,如果值在到达第二个原子操作所需的时间内没有改变,我们执行减量,然后做一些工作。如果我们先发制人,那我们就再试一次。

你的假设 这或多或少是正确的
(无符号)0-1将是最大的无符号整数。你的原子减量总是会发生,即使条件是假的

我们如何解决这个问题? 我相信你实际上在寻找这样的东西:

std::atomic<uint_fast64_t> counter;
while (true) {
    uint_fast64_t cur = counter;
    if (cur == 0)
        break;
    if (counter.compare_exchange_strong(cur, cur - 1) == false)
        continue;

    ... // Perform work
} 
std::原子计数器;
while(true){
uint\u fast64\u t cur=计数器;
如果(cur==0)
打破
if(计数器比较交换强(cur,cur-1)=false)
持续
…//执行工作
} 
首先,我们测试计数器的当前值是否为0。如果是的话,我们工作完了,我们应该辞职


如果它大于0,那么我们需要减小计数器。这是一个比较和交换操作。因此,如果值在到达第二个原子操作所需的时间内没有改变,我们执行减量,然后做一些工作。如果我们先发制人,那我们就再试一次。

当然,你让它这么做的。若计数器为零,则递减并退出。现在,所有其他线程都在猛烈地递减现在非常高的计数器,没有希望取得重大进展。为什么不在while循环中减去?@ Moberg:考虑两个线程的情况。两者都进入while循环,因为
计数器==1
。然后,一旦两者都进入循环,它们都会减小计数器的值。现在是
counter==-1
。正如Bill Lynch所说,如果在两个不同的位置执行变量求值和减量,你不能保证在此期间没有其他人执行相同的操作
while(counter-->NThreads)
没有比
while(counter++
。当然可以,是你让它这么做的。若计数器为零,则递减并退出。现在,所有其他线程都在猛烈地递减现在非常高的计数器,没有希望取得重大进展。为什么不在while循环中减去?@ Moberg:考虑两个线程的情况。两者都进入while循环,因为
计数器==1
。然后,一旦两者都进入循环,它们都会减小计数器的值。现在是
counter==-1
。正如Bill Lynch所说,如果在两个不同的位置执行变量求值和减量,你不能保证在此期间没有其他人执行相同的操作
while(counter-->NThreads)
没有比
while(counter++
操作符--
std::atomic
上应该是原子的,不是吗?我是真的