如何使用std :: lock_guard锁定对std :: map的读写权限?

时间:2012-08-23 22:33:39

标签: c++ exception c++11 native mutex

当我在MSVC 2012中逐步执行以下代码时 我在第3行和第8行放置一个断点。

第一次突破就在第8行。

lock_guard被称为正常,然后我们在第3行打破。 这次,由于已经获得锁定,当我跳过时会抛出异常。

我真的希望它继续前进,因为它仍然是相同的线程调用(我们只是来自第11行。)

还有其他更适合这种情况的锁定机制吗?

我有本机win32编程的背景所以我习惯了WaitForSingleObject,这会让我毫不费力地通过这里, 但是lock_guard没有。

我应该处理这个例外吗?我见过的所有例子都没有针对lock_guard的任何异常处理程序......

有没有更好的方法来确保一次不能通过多个线程访问地图? 我需要写入和读取锁定,而lock_guard似乎是一个平滑的选择,因为我没有ReleaseMutex ......

    //Cars.h
    mutable std::mutex carsMutex;
    class Cars
    {
    private:
        std::map<std::string,Cars> _cars;
    public:
        virtual ~Cars() {}
        Cars() {}
        Cars & operator[](const std::string &key);
        Cars & operator[](const DWORD &key);
        std::string color;
    };

    //Cars.cpp
      #include "Cars.h"
1.    Cars & Cars::operator[](const std::string &key)
2.    {
3.        std::lock_guard<std::mutex> lock_a(carsMutex);
4.        return _cars[key];
5.    }
6.    Cars & Cars::operator[](const DWORD &key)
7.    {
8.        std::lock_guard<std::mutex> lock_a(carsMutex);
9.        std::stringstream ss;
10.       ss << key;
11.       return operator[](ss.str());
12.   }
14.   void main()
15.   {
16.       //ok i have multiple threads like this one writing and reading from the map
17.       Cars cars;
18.       cars[(DWORD)2012]["volvo"].color = "blue";
19.   }

更新 这是我对上面代码的编辑。 我已经考虑到了答案,这是我尝试正确使用std :: lock_guard的新尝试 如果不正确,请评论。

    //Cars.h
    mutable std::recursive_mutex carsMutex;
    class Cars
    {
    private:
        std::string _color;
        std::map<std::string,Cars> _cars;
    public:
        virtual ~Cars() {}
        Cars() {}
        Cars & operator[](const std::string &key);
        Cars & operator[](const DWORD &key);
        void color(const std::string &color);
        std::string color();
    };

       //Cars.cpp
       #include "Cars.h"
 1.    Cars & Cars::operator[](const std::string &key)
 2.    {
 3.        std::lock_guard<std::recursive_mutex> lock(carsMutex);
 4.        return _cars[key];
 5.    }
 6.    Cars & Cars::operator[](const DWORD &key)
 7.    {
 8.        std::lock_guard<std::recursive_mutex> lock(carsMutex);
 9.        std::stringstream ss;
10.        ss << key;
11.        return operator[](ss.str());
12.    }
13.    void color(const std::string &color)
14.    {
15.        std::lock_guard<std::recursive_mutex> lock(carsMutex);
16.        _color = color;
17.    }
18.    std::string color()
19.    {
20.        std::lock_guard<std::recursive_mutex> lock(carsMutex);
21.        return _color;
22.    }
23.
24.    Cars cars;//this is global...
25.    void main()
26.    {
27.        //ok i have multiple threads like this one writing and reading from the map
28.        cars[(DWORD)2012]["volvo"].color("blue");
29.    }

1 个答案:

答案 0 :(得分:4)

要允许线程重新获取已有的互斥锁,您需要std::recursive_mutex而不是std::mutex

但是,您遇到了一个更大的问题:您的访问者在返回您用于分配地图元素的引用之前解锁互斥锁,因此分配本身是无人看管的。这可以通过编写“setter”函数来修复,该函数在返回之前执行赋值;或者通过返回包含在其析构函数中释放的互斥锁的代理对象。解决此问题可能会消除对recursive_mutex的需求。