在多线程环境中使用atomic保护两个变量

protect two variables with atomic in a multi-threading environement

本文关键字:变量 两个 保护 atomic 环境 多线程      更新时间:2023-10-16

//线程1

std::uint64_t getAndResetProcessingTimeInMicro()
{
    auto value = m_cumulatedProcessingTimeCount.load(boost::memory_order_acquire);
    if (value == 0)
        return 0;
    auto processingTime = m_cumulatedProcessingTime.load(boost::memory_order_relaxed);
    resetProcessingTimeInMicro();
    return processingTime / value;
}

//线程2

void addProcessingTimeInMicro(std::uint64_t processedTime)
{ 
    m_cumulatedProcessingTime.fetch_add(processedTime, boost::memory_order_relaxed); 
    //ctxt switch here  //-----HERE------
    m_cumulatedProcessingTimeCount.fetch_add(1, boost::memory_order_release);
}

线程1计算处理时间的平均值,线程2累加处理时间。

我想确保上下文开关在不引入锁的情况下无法在HERE位置获取数据,我可以通过使用原子对象来实现这个结果吗?

如果要同时执行两个不同的原子操作,则在写入和读取它们时都需要一个互斥体。互斥不会阻止上下文切换,但使用这种方式可以保证您不会访问半更新的状态。

或者,如果您真的不想使用互斥,可以使用单个uint64_t的64位中的一些来存储计数(比如较低的8)。然后你会

m_cumulatedProcessingTime.fetch_add((processedTime << 8) + 1, boost::memory_order_release);

然后检索

auto value = m_cumulatedProcessingTimeCount.load(boost::memory_order_acquire);
auto time = value >> 8;
auto count = value & 0xff;

你可以,但你可能不想。

您需要对包含这两个变量的结构使用原子shared_ptr。读取的过程只是原子地复制shared_ptr,并查看它指向的结构。写入的过程是:

  1. 读取原子shared_ptr

  2. 根据结构中的新值,分配(使用std::make_shared)一个新结构,该结构包含两个变量的新值。

  3. 尝试原子比较/交换,将原子shared_ptr设置为指向新结构。

  4. 如果比较/交换成功,则完成。

  5. 释放您创建的新结构,然后返回步骤1。(你可以保证其他作家取得了进步。)

不过你真的不想这么做。只要用一把锁。

生成这样的并集:

union CData {
  struct {
    __int32   a;
    __int16   c;
    __int16   d:2,
              e:14;
    // you get the idea...
  }
  __int64     n64;
}

使用结构成员使用所有变量,使用n64执行原子操作。