【问题标题】:Using InterlockedIncrement to increment STL map's value field. Is it threadsafe?使用 InterlockedIncrement 增加 STL 映射的值字段。它是线程安全的吗?
【发布时间】:2014-07-30 00:59:12
【问题描述】:

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

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);
}

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

【问题讨论】:

  • 不,在一个线程中读取变量并在另一个线程中修改它绝不是线程安全的。你需要一个真正的锁,就像一个互斥锁。
  • 我希望你的意思是绝对没有删除和插入..

标签: multithreading map stl thread-safety interlocked-increment


【解决方案1】:

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

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

在表达式(1) 中读取内存位置itr-&gt;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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-23
    • 2015-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多