2

我有一个这样定义的地图。

typedef std::map< tstring, unsigned int >  ErrorToCount_T;
ErrorToCount_T m_ErrorToSuppress;

我像这样使用它。

ErrorToCount_T::iterator itr = m_ErrorToSuppress.find( val );
if( itr != m_ErrorToSuppress.end())
{
    if( (itr->second) % m_LogFreq == 0)
        //Do something
    else
        //Do something else
    InterlockedIncrement( &itr->second);
}

我看到了这个,我明白 find 是线程安全的。但我在想 InterlockedIncrement( &itr->second) 也会是线程安全的吗?上面的代码线程安全吗?在多线程环境中,此映射中绝对没有插入。

4

1 回答 1

0

如果两个线程使用相同的键(即val)执行代码,则以下列表中标有(1)和的表达式(2)可能会同时执行:

if( (itr->second) % m_LogFreq == 0) // (1)
    //Do something
else
    //Do something else
InterlockedIncrement( &itr->second); // (2)

在表达式中读取(1)内存位置itr->second,在表达式(2)中写入。这称为数据竞争,C++11 标准规定,如果程序包含数据竞争,则程序的行为是未定义的。

只要您的编译器供应商没有为您提供有关内存模型的额外保证,您就必须使用不会导致数据竞争的操作。使用 C++11,它可能如下所示:

using ErrorToCount = std::map<tstring, std::atomic<unsigned int>>;
ErrorToCount errorToSuppress;

ErrorToCount::iterator itr = errorToSuppress.find( val );
if( itr != errorToSuppress.end()) {
    if (itr->second.load(std::memory_order_seq_cst) % m_LogFreq == 0)
        //Do something
    else
        //Do something else
    itr->second.fetch_add(1, std::memory_order_seq_cst);
}
于 2014-06-09T14:22:44.097 回答