发布获取语义以计算平均值 [英] Release Acquire Semantics to Compute Average

查看:99
本文介绍了发布获取语义以计算平均值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说有两个函数可以更新并返回要测量的某些属性的平均值:

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.

假设在Update()的同一对象上没有并发调用,但是对于Update()GetAverage()的同一对象可能没有并发调用.

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().

对于我所阅读的内容,GetAverage()m_count的获取负载禁止在m_accumulatedValue之前同时重载m_accumulatedValue 的负载,以确保对一旦还看到了对m_count的更改,则调用GetAverage()的线程可以看到由Update()执行的m_accumulatedValue,因为Update()m_cout上执行的存储具有发布顺序.

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.

我刚才说的对吗?

GetAverage()(在保证对Update()的调用不并发的前提下)是否总是返回正确的答案?还是有一种方法可以返回计算出的平均值,其中某些值比其他值更新得更多"?

Does GetAverage() (with the said guarantee of non-concurrency of the calls to Update()) always return the right answer? Or there can be a way of it returning the calculated average with some of the values "more updated" than the other?

m_accumulatedValue根本不需要原子吗?

推荐答案

您对获取/释放语义的工作方式的描述是正确的; 它们用于在存储/释放之前和加载/获取之后的内存操作之间创建线程间 happens-before 关系. 这是基于运行时关系的,并且仅在 定义,如果原子加载/获取看到存储/发布设置的值.

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.

您的代码的第一个问题是它无法满足运行时要求. m_count的值没有被检查,因此订购保证不适用.因此,您也可以在所有操作上都使用memory_order_relaxed.

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; you could therefore as well have used memory_order_relaxed on all operations.

但是,仅靠这一点并不能解决问题.当您阅读m_accumulatedValue时,它的值可能会通过再次调用Update()再次更改(因此,m_accumulatedValue必须是原子的). 此外,正如注释部分所指出的,由于原子操作之间没有原子性,因此GetAverage()可能在Update()完成并返回错误值之前被调用.

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). 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.

您需要的是在Update()GetAverage()之间严格排序,而最好的方法是使用std::mutex.然后,原子变量可以是正整数(如果未在其他地方使用).

What you need is strict ordering between Update() and GetAverage() and the best way to do that is with a std::mutex. The atomic variables can then be regular integers (if not used elsewhere).

这篇关于发布获取语义以计算平均值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆