Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
339 views
in Technique[技术] by (71.8m points)

c++ - Safe and effective way to put a mutex on a container entry

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...