【问题标题】:thread safety of find() from a STL container of std::unique_ptr来自 std::unique_ptr 的 STL 容器的 find() 线程安全
【发布时间】:2017-02-01 07:39:33
【问题描述】:

示例代码。

class Obj
{
    public:
    void doSome(void)
    {
        std::cout << "Hello World!" << std::endl;
    }
};

std::unordered_map<int, std::unique_ptr<Obj>> map;

// insert -- done with single thread and before find()
map[123] = std::move( std::unique_ptr<Obj>(new Obj) );

// find -- run from multiple threads
auto search = map.find(123);  // <=== (Q)
if (search != map.end())      
{
  search->second->doSome();
}

(问)

如果有多个线程使用 ma​​p.find(123) 运行 //find 部分,线程安全性如何?

ma​​p.find(123) 是否总能在每个线程 中找到obj?只要search->second没有分配给别人?

【问题讨论】:

  • 注意:不要移动函数返回的任何东西(任何没有变量名的东西)。没用。
  • 一般规则是调用标准库类的const成员函数(如find)是可以的,只要不并发调用非const函数即可。

标签: c++ c++11 stl unique-ptr


【解决方案1】:

当多个线程访问同一个变量并且其中至少有一个线程写入它时,您就会发生数据竞争。这不是这里的情况,每个人都在读取相同的数据。没关系。但是,还有另一个问题,此代码未解决:根据数据存储到地图对象的时间,某些线程可能看不到地图对象的更新版本。处理此同步问题的最简单方法是在创建任何读取器线程之前设置映射对象。

【讨论】:

  • 关于你答案的第二部分:当地图对象只设置而另一个线程可能已经在读取它时,这不是数据竞争吗?
  • @ChristianHackl - 是的,数据竞争可能涉及同时读取和写入。我回答的第二部分不是关于数据竞赛,而是关于变化的可见性。例如:如果映射是由一个线程创建的,则更改的结果可能在运行该线程的处理器缓存中,而在不同处理器上运行的其他线程可能缓存了旧值,因此他们不会看到更新。新创建的线程将始终看到创建它的线程所做的所有全局更改,这就是为什么在映射初始化之前不创建线程可以解决问题。
【解决方案2】:

find() 和无序映射中的任何其他方法都不是线程安全的。如果一个执行线程可能调用find(),而任何其他线程调用任何修改它的无序映射方法,这将导致未定义的行为。

如果多个执行线程使用相同的键调用find(),前提是没有未定义的行为,所有执行线程都将为该键获得相同的值。

【讨论】:

    猜你喜欢
    • 2018-09-30
    • 2013-05-05
    • 2012-10-07
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 2021-12-19
    • 1970-01-01
    相关资源
    最近更新 更多