在多线程环境中用原子保护两个变量
protect two variables with atomic in a multi-threading environement
//线程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;
像这样建立联合:
union CData {
struct {
__int32 a;
__int16 c;
__int16 d:2,
e:14;
// you get the idea...
}
__int64 n64;
}
使用结构成员的所有变量,用 n64 做原子的事情。
你可以,但你可能不想。
您需要一个 atomic shared_ptr 到包含两个变量的结构。读取的过程只是原子地复制 shared_ptr
并查看它指向的结构。写入过程为:
读取原子shared_ptr
.
分配(使用 std::make_shared
)一个新结构,其中包含基于结构中变量的两个变量的新值。
尝试一个原子 compare/exchange 来设置原子 shared_ptr 指向你的新结构。
如果 compare/exchange 成功,您就完成了。
释放您创建的新结构并返回到第 1 步。(保证其他作者取得了进展。)
虽然你真的不想这样做。就用一把锁吧。
//线程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;
像这样建立联合:
union CData {
struct {
__int32 a;
__int16 c;
__int16 d:2,
e:14;
// you get the idea...
}
__int64 n64;
}
使用结构成员的所有变量,用 n64 做原子的事情。
你可以,但你可能不想。
您需要一个 atomic shared_ptr 到包含两个变量的结构。读取的过程只是原子地复制 shared_ptr
并查看它指向的结构。写入过程为:
读取原子
shared_ptr
.分配(使用
std::make_shared
)一个新结构,其中包含基于结构中变量的两个变量的新值。尝试一个原子 compare/exchange 来设置原子 shared_ptr 指向你的新结构。
如果 compare/exchange 成功,您就完成了。
释放您创建的新结构并返回到第 1 步。(保证其他作者取得了进展。)
虽然你真的不想这样做。就用一把锁吧。