关于 map::operator[] 的数据竞争

Data race about map::operator[]

这个code snippet有什么潜在的问题吗?

#include <mutex>
#include <map>
#include <vector>
#include <thread>

constexpr int FOO_NUM = 5;

int main()
{
std::map<int, std::mutex> mp;

std::vector<std::thread> vec;
for(int i=0; i<2; i++)
{
    vec.push_back(std::thread([&mp](){
    std::lock_guard<std::mutex> lk(mp[FOO_NUM]); //I think there is some potential problem here, am I right?
    //do something
     }));
}

for(auto& thread:vec)
{
thread.join();
}

根据 the document,即:

Inserts value_type(key, T()) if the key does not exist. This function is equivalent to return insert(std::make_pair(key, T())).first->second;

我认为上述代码片段中存在潜在问题。你看这可能会发生:

1.the 第一个线程创建了一个 mutex,并且正在锁定 mutex

2.the第二个线程创建了一个新的,第一个线程中创建的mutex需要销毁,而它仍在第一个线程中使用。

operator[] 的关联容器和无序容器未指定为在多线程中未经同步调用时不会发生数据竞争。参见 [container.requirements.dataraces]/1

因此您的代码存在数据竞争,因此存在未定义的行为。是否创建新的互斥量也无关紧要。

是的,存在数据竞争,但它更为根本。

C++ 库中的容器

None 无论如何都是 thread-safe。 None 他们的运营商是线程安全的。

mp[FOO_NUM]

在显示的代码中,多个执行线程调用映射的 [] 运算符。这不是 thread-safe,运营商本身。地图中包含的内容无关紧要。

the second thread created a new one, and the mutex created in the first thread needs to be destroyed while it's still used in the first thread.

main().

返回时,当地图本身被销毁时,所示代码中唯一会破坏任何互斥体的是地图的析构函数

std::lock_guard<std::mutex> 而不是 销毁它的互斥锁,当 std::lock_guard 被销毁并释放互斥锁时,当然。执行线程对映射的 [] 运算符的调用可能 default-construct 一个新的 std::mutex,但是当执行线程加入时没有任何东西会破坏它。 std::map 中的 default-constructed 值,由其 [] 运算符,仅当某些内容 显式 [=38= 时才会被销毁] 摧毁它。

而且 [] 运算符本身不是线程安全的,它与互斥锁的构造或销毁无关。