Home > database >  Data race about map::operator[]
Data race about map::operator[]

Time:03-31

Is there any potential problem in this 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();
}

As per the document,which says that:

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;

I think there is a potential problem in the aforementioned code snippet. You see this may happen:

1.the first thread created a mutex, and is locking the mutex.

2.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.

CodePudding user response:

Yes, there is a data race, but it is even more fundamental.

None of the containers in the C library are thread-safe, in any way. None of their operators are thread safe.

mp[FOO_NUM]

In the shown code multiple execution threads invoke map's [] operator. This is not thread-safe, the operator itself. What's contained in the map is immaterial.

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.

The only thing that destroys any mutex in the shown code is the map's destructor when the map itself gets destroyed when returning from main().

std::lock_guard<std::mutex> does not destroy its mutex, when the std::lock_guard gets destroyed and releases the mutex, of course. An execution thread's invocation of the map's [] operator may default-construct a new std::mutex, but there's nothing that would destroy it when the execution thread gets joined. A default-constructed value in a std::map, by its [] operator, gets destroyed only when something explicitly destroys it.

And it's the [] operator itself that's not thread safe, it has nothing to do with a mutex's construction or destruction.

CodePudding user response:

operator[] of associative and unordered containers is not specified to be safe from data races if called without synchronization in multiple threads. See [container.requirements.dataraces]/1.

Therefore your code has a data race and consequently undefined behavior. Whether or not a new mutex is created doesn't matter either.

  • Related