简体   繁体   English

发布获取语义以计算平均值

[英]Release Acquire Semantics to Compute Average

Say there are two functions to update and return the average of some property being measured: 假设有两个函数需要更新并返回一些被测属性的平均值:

void Class::Update( int delta )
{
    m_accumulatedValue += delta;
    ++ m_count;
}

double Class::GetAverage( )
{
    return m_accumulatedValue/(double)m_count;
}

Now, suppose they need to be changed to run in a multithreaded environment with a thread pool in which any thread can be requested to execute one of them - that is, the thread executing each one of them can be a different one each time: 现在,假设需要将它们更改为在具有线程池的多线程环境中运行,其中可以请求任何线程执行其中一个线程 - 也就是说,每次执行其中每个线程的线程可以是不同的线程:

std::atomic< int > m_accumulatedValue;
std::atomic< int > m_count;

// ...

void Class::Update( int delta )
{
    m_accumulatedValue.fetch_add( delta , std::memory_order_relaxed );
    m_count.fetch_add( 1 , std::memory_order_release );
}

double Class::GetAverage( )
{
    auto count = m_count.load( std::memory_order_acquire );
    auto acc = m_accumulatedValue.load( std::memory_order_relaxed );

    return acc/(double)count;
}

I'm trying to understand the acquire and release memory orderings. 我正在尝试理解获取和释放内存排序。

Suppose there's no concurrent calls on the same object for Update() , but may be concurrent calls on the same object for Update() and GetAverage() . 假设Update()对同一对象没有并发调用,但可能是对Update()GetAverage()的同一对象的并发调用。

For what I've read, the acquire load of m_count in GetAverage() forbids the reordering of the load of m_accumulatedValue before it and at the same time guarantees that any change to m_accumulatedValue performed by Update() is visible by the thread calling GetAverage() once the change to m_count is also seen, for the store performed on m_cout by Update() has a release ordering. 对于我所读过的m_countGetAverage()GetAverage()的获取负载禁止在它之前重新排序m_accumulatedValue的负载, 同时保证调用GetAverage()的线程可以看到Update()执行的对m_accumulatedValue任何更改都是可见的。 GetAverage()一旦看到对m_count的更改,对于由Update()m_cout执行的存储具有释放顺序。

Is what I've just said right? 我刚刚说的是对的吗?

Does GetAverage() (with the said guarantee of non-concurrency of the calls to Update() ) always return the right answer? GetAverage() (具有对Update()调用的非并发性的上述保证)是否始终返回正确的答案? Or there can be a way of it returning the calculated average with some of the values "more updated" than the other? 或者有一种方法可以返回计算出的平均值,其中一些值比另一些更“更新”?

Does m_accumulatedValue need to be atomic at all? m_accumulatedValue是否需要是原子的?

Your description of how acquire/release semantics work is correct; 您对获取/释放语义如何工作的描述是正确的; they are used to create an inter-thread happens-before relationship between memory operations before the store/release and after the load/acquire... This is based on a run-time relationship and is only defined if the atomic load/acquire sees the value that was set by the store/release. 它们用于创建存储/释放之前和加载/获取之后的内存操作之间的线程间发生关系...这基于运行时关系,并且在原子加载/获取看到时才定义存储/发布设置的值。

The first problem with your code is that it fails to meet this run-time requirement. 您的代码的第一个问题是它无法满足此运行时要求。 The value of m_count is not checked and therefore the ordering guarantees do not apply; 未检查m_count的值,因此订购保证不适用; you could therefore as well have used memory_order_relaxed on all operations. 因此,您可以在所有操作中使用memory_order_relaxed

But that alone does not solve the problem; 但仅凭这一点并不能解决问题; when you read m_accumulatedValue , its value may have changed again by another call to Update() ( m_accumulatedValue therefore has to be atomic). 当你读取m_accumulatedValue ,它的值可能会再次被另一个Update()调用改变(因此m_accumulatedValue必须是原子的)。 Futhermore, as pointed out in the comments section, since there is no atomicity between the atomic operations, GetAverage() may be called before Update() is finished and return an incorrect value. 此外,正如注释部分所指出的,由于原子操作之间没有原子性, GetAverage()可以在Update()完成之前调用GetAverage()并返回不正确的值。

What you need is strict ordering between Update() and GetAverage() and the best way to do that is with a std::mutex . 你需要的是Update()GetAverage()之间的严格排序,最好的方法是使用std::mutex The atomic variables can then be regular integers (if not used elsewhere). 然后原子变量可以是常规整数(如果不在其他地方使用)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM