Safe and effective way to put a mutex on a container entry

五迷三道 提交于 2020-01-09 19:23:10

问题


C++'s std::mutex does not have a move constructor. There is a good reason for that. Basically, move constructors themselves are not generally thread safe, and the whole point of a mutex is that multiple threads will be trying to access it simultaneously.

An unfortunate implication of this is that a mutex cannot be placed into a container directly. Containers need the ability to safely move their contents around, and you can't do that with a mutex.

The easy way out is to just protect the entire container with a single separate mutex. But suppose I want finer-grained control than that? If I'm implementing a database via a container (eg: std::map), it seems reasonable to want the ability to lock individual records, not just the whole database.

The next thing that comes to mind is to hack around the problem by using std::unique_ptr. That would compile, but it doesn't really change the basic problem, does it? The scenario where there's a problem with move is where thread1 makes a container change that causes an entry move while thread2 is in the middle of using that container entry. In this scenario, thread2 could just as easily end up holding a destructed entry or smart pointer. It seems like no matter what, you end up having to lock the entire container with a mutex before doing anything.

It seems like there ought to be a known idiom for doing these kinds of things.


回答1:


The mutex does not require to be moved:

Imagine that every row in your map is like:

template <class T>
class row
{
    shared_ptr<mutex> m;
    T data;
    ...
};

So if your row need to be moved or copied, there is no problem.

Then, you may access the mutex from every process to access the data.

Of course, you need a global mutex to perform changes on the whole map: insert / delete / [] / any other operation that change the state of the map.

EDITED:

Following a simple example of code with a mutex in every row. (It does not implement anything else that just the data structure)

#include <memory>
#include <map>
#include <mutex>

template <class T>
class row
{
    std::shared_ptr<std::mutex> m;
    T data;
public:
    row( std::shared_ptr<std::mutex> mut): m(mut){};
};

auto main () -> int
{
    std::shared_ptr<std::mutex> mut(new std::mutex);
    std::map<int,row<int>> db;
    row<int> a(mut);
    db.insert(std::pair<int, row<int>>(1, a));
    return 0;
}


来源:https://stackoverflow.com/questions/27276555/safe-and-effective-way-to-put-a-mutex-on-a-container-entry

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!