我有一个静态地图作为我班级的成员变量。当我们必须访问这个地图时,我们需要有静态锁吗?
4 回答
如果您的std::map
实例被声明为类静态,那么您的锁也需要是类静态的。
当锁是非静态成员但映射是时,考虑使用映射处理单独对象的两个线程。
- 对象 1 锁定本地锁并开始操作共享映射。
- 对象 2 锁定其本地锁(记住,它是一个单独的锁)并开始操作共享映射。
- 繁荣/崩溃/燃烧
如果锁是类静态的,两个对象会共享锁,上面的场景也可以正常工作,一次只能有一个线程加锁。
当然还有其他方法可以在不使用的情况下共享锁static
,但这似乎不是你要问的。
每个对象都需要一个mutex
必须以同步方式使用的对象。一个对象有多个互斥体将导致竞争条件,如 Joachim Isaksson 在他的回答中给出的示例所示。
static
变量有多种方式:
类静态(这可能是你的意思):
class X { static map<A,B> mMap; };
您在系统范围内只有一个对象。在这种情况下,映射的互斥锁也应该是类静态的,并且每当映射以需要同步的方式使用时都应该被锁定。请记住,类静态成员的初始化不是线程安全的。
函数局部静态:
class X { void foo() { static map<A,B> theMap{ /* ... */ }; } };
你有一个系统范围的对象,不管
foo
它本身是否是静态类。该对象的初始化保证是线程安全的。您还需要一个系统范围内的互斥锁。该互斥锁应该是内部的静态foo
或类静态或全局的。在后两种情况下,必须在每次调用foo
. 这是 Meyers 单例的经典用例:class X { static mutex mapMutex; static map<A,B>& getMap() { static map<A,B> theMap{ /* ... */ }; return theMap; } void useMap() { lock myLock(mutex); getMap()[a] = b; } };
翻译单元静态(“全局静态”)
static map<A,B> gMap; class X { /* ... */ };
您在每个具有此类声明的翻译单元内都有一个对象,即如果它在.cpp 内,您将获得一个对象。如果它位于标头内,您会为每个包含该标头的翻译单元获得一个对象。该对象的互斥锁也应该是静态翻译单元,因为您需要与对象一样多的互斥锁。但是,我不建议在多线程环境中使用这种静态变量。
首先,您应该考虑阅读static
(也许试试这个)。那是因为含义static
取决于上下文。
但这可能是一个并发症,我相信你有这样的事情:
class A {
private:
static std::map....
public:
void doSomethingWithMap() {
//lock mutex
//some action with map
//unlock mutex
}
}
如果是这种情况,那么您可能希望将互斥锁作为此类的成员。这就是重点——这取决于您需要的范围。如果你需要在这个类的所有对象上全局锁定——你应该考虑使用静态类成员,如果你想锁定每个对象——你应该只使用一个类成员。
不,通常您不需要静态锁。