【问题标题】:Are functions called by a concurrent unordered map look-up thread safe?由并发无序映射查找线程调用的函数是否安全?
【发布时间】:2018-09-13 16:00:51
【问题描述】:

假设我有以下代码:

#include<concurrent_unordered_map.h>

struct firstStruct {
<irrelevant code>
}
struct secondStruct {
    void func(){ 
       <CRITICAL CODE>
    }
}

假设我有这个:

concurrent_unordered_map<firstStruct,secondStruct> cmap = ...

让我们假设cmap 已被填充,并且firstStruct fsecondStruct s(key,value)(f,s) 存在于cmap 中。

如果我使用下面的代码 sn-p

cmap[f].func();

secondStruct s 执行func() 中的&lt;CRITICAL CODE&gt; 是否是线程安全的?

另外,如果我有以下代码 sn-ps,可能会在不同线程中同时执行,会发生什么?

cmap[f].func();

SecondStruct s2 = ... ;
cmap[f] = s2;

如果(key,value)(f,s)被一个线程更改为(f,s2),如果另一个线程恰好正在执行&lt;CRITICAL CODE&gt;会发生什么?

【问题讨论】:

    标签: c++ multithreading visual-studio concurrency thread-safety


    【解决方案1】:

    proposalconcurrent_unordered_map

    对于序列化执行,操作的行为与其当前的 STL 对应项相同。唯一的变化是允许并发。在并发无序容器上同时执行以下任何操作不会引入数据竞争:

    get_allocator
    empty, size, max_size
    begin, end, cbegin, cend
    insert
    find, count, equal_range, operator[], at
    load_factor
    max_load_factor() 
    operator==, operator!= 
    

    假设对键类型(和 mapped_type,如果适用)的必要操作是并发安全的。

    强调我的

    所以,operartor[] 是线程安全的,但您使用它的返回值执行的操作也必须是线程安全的,以保证不会发生数据竞争。这意味着func() 中的&lt;CRITICAL CODE&gt; 本身必须是线程安全的。如果不是,那么类似

    cmap[f].func();
    SecondStruct s2 = ... ;
    cmap[f] = s2;
    

    也不会是线程安全的,因为当您将新对象分配给键时,该函数仍会运行。

    【讨论】:

    • 非常感谢!这消除了我在代码中几个地方的一些疑问。为了解决这个问题,我考虑将cmap 更改为:concurrent_unordered_map&lt;firstStruct,std::shared_ptr&lt;secondStruct&gt;&gt; cmap = ... 并像这样调用 func:std::shared_ptr&lt;secondStruct&gt; temp_ptr = cmap[f]; temp_ptr-&gt;func(); 这会是线程安全的吗?通常有没有更好的方法来做到这一点,同时保持线程安全并确保快速执行?在这一点上我应该指出,速度在我的代码中很重要。
    • @glopquestions 只要没有人做类似*cmap[f] = s2; 的事情(分配给指向的对象而不是分配一个新指针),那将是线程安全的。如果他们分配了一个新的指针,你会没事的,但如果他们改变了你身上的底层对象,那么你就在同一条船上。
    • 我在考虑使用cmap[f] = std::make_shared&lt;secondStruct&gt;(s2); 分配这是线程安全的吗? (只是为了澄清,将 f 映射到同一个共享指针但更改共享指针指向的内容(我想要的不同的东西)是危险的),但是(将 f 映射到新的共享指针并拥有这个新的共享指针指向我想要的任何东西都是安全的?)
    • @glopquestions 是的,那将是线程安全的。 cmap[f] 将被重新分配给 std::make_shared&lt;secondStruct&gt;(s2),但由于 temp_ptr 存在,那么您调用该函数的对象仍然存在。
    • @glopquestions 线程安全是一个相对属性。询问单个操作是否是线程安全的属于类别错误。询问两个或多个操作是否相对线程安全是有意义的。您甚至可以询问同一操作的两次调用是否对彼此是线程安全的。这些 cmets 中的代码有一些线程安全的操作;这些 cmets 中的代码还有其他不是线程安全的操作。如果你问你的做法,对方必须读懂你的想法,如果他们弄错了,他们会给出错误的答案,而你会幸福地浑然不觉。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 2018-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多