我有一个这样定义的映射。
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);
}
我看到了这个,我明白这个发现是线程安全的。但我在想,InterlockedIncrement(&itr->second(也会是线程安全的吗?上面的代码线程安全吗。在多线程环境中,此映射中绝对没有插入。
如果两个线程使用相同的键(即val
(执行代码,则以下列表中标记为(1)
和(2)
的表达式可能会同时执行:
if( (itr->second) % m_LogFreq == 0) // (1)
//Do something
else
//Do something else
InterlockedIncrement( &itr->second); // (2)
在表达式 只要编译器供应商没有为您提供关于内存模型的额外保证,您就必须使用不会导致数据争用的操作。使用C++11,它可能看起来如下:(1)
中,读取存储器位置itr->second
,而在表达式(2)
中,写入该存储器位置。这被称为数据竞赛,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);
}