gpt4 book ai didi

c++ - 防止 std::atomic 溢出

转载 作者:可可西里 更新时间:2023-11-01 17:41:32 26 4
gpt4 key购买 nike

我有一个原子计数器 ( std::atomic<uint32_t> count ),它向多个线程处理顺序递增的值。

uint32_t my_val = ++count;

在我得到 my_val 之前我想确保增量不会溢出(即:回到0)

if (count == std::numeric_limits<uint32_t>::max())
throw std::runtime_error("count overflow");

我认为这是一个天真的检查,因为如果在递增计数器之前由两个线程执行检查,则第二个要递增的线程将返回 0

if (count == std::numeric_limits<uint32_t>::max()) // if 2 threads execute this
throw std::runtime_error("count overflow");
uint32_t my_val = ++count; // before either gets here - possible overflow

因此我想我需要使用 CAS操作以确保当我递增我的计数器时,我确实在防止可能的溢出。

所以我的问题是:

  • 我的实现是否正确?
  • 它是否尽可能高效(具体来说,我需要检查 max 两次)吗?

我的代码(带有工作范例)如下:

#include <iostream>
#include <atomic>
#include <limits>
#include <stdexcept>
#include <thread>

std::atomic<uint16_t> count;

uint16_t get_val() // called by multiple threads
{
uint16_t my_val;
do
{
my_val = count;

// make sure I get the next value

if (count.compare_exchange_strong(my_val, my_val + 1))
{
// if I got the next value, make sure we don't overflow

if (my_val == std::numeric_limits<uint16_t>::max())
{
count = std::numeric_limits<uint16_t>::max() - 1;
throw std::runtime_error("count overflow");
}
break;
}

// if I didn't then check if there are still numbers available

if (my_val == std::numeric_limits<uint16_t>::max())
{
count = std::numeric_limits<uint16_t>::max() - 1;
throw std::runtime_error("count overflow");
}

// there are still numbers available, so try again
}
while (1);
return my_val + 1;
}

void run()
try
{
while (1)
{
if (get_val() == 0)
exit(1);
}

}
catch(const std::runtime_error& e)
{
// overflow
}

int main()
{
while (1)
{
count = 1;
std::thread a(run);
std::thread b(run);
std::thread c(run);
std::thread d(run);
a.join();
b.join();
c.join();
d.join();
std::cout << ".";
}
return 0;
}

最佳答案

是的,您需要使用 CAS操作。

std::atomic<uint16_t> g_count;

uint16_t get_next() {
uint16_t new_val = 0;
do {
uint16_t cur_val = g_count; // 1
if (cur_val == std::numeric_limits<uint16_t>::max()) { // 2
throw std::runtime_error("count overflow");
}
new_val = cur_val + 1; // 3
} while(!std::atomic_compare_exchange_weak(&g_count, &cur_val, new_val)); // 4

return new_val;
}

思路如下:一次g_count == std::numeric_limits<uint16_t>::max() , get_next()函数将始终抛出异常。

步骤:

  1. 获取计数器的当前值
  2. 如果它是最大的,抛出一个异常(不再有可用的数字)
  3. 获取新值作为当前值的增量
  4. 尝试自动设置新值。如果我们设置失败(已经由另一个线程完成),请重试。

关于c++ - 防止 std::atomic 溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16784708/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com