我有一个静态地图作为我班级的成员变量。 当我们必须访问这张地图时,我们是否需要静态锁定?
答案 0 :(得分:4)
如果你的std::map
实例被声明为静态类,那么你的锁也需要是类静态的。
当锁是非静态成员但地图是。时,考虑两个线程使用地图对单独的对象进行处理。
如果锁是静态类,则两个对象将共享锁,并且上述方案将运行良好,一次只能锁定一个线程。
当然有其他方法可以在不使用static
的情况下共享锁定,但这似乎不是您所要求的。
答案 1 :(得分:0)
每个对象只需要一个mutex
,必须以同步的方式使用。拥有一个对象的多个互斥锁将导致竞争条件,如Joachim Isaksson在其答案中给出的示例所示。
static
变量有不同的方法:
类静态(可能是你的意思):
class X {
static map<A,B> mMap;
};
系统范围内只有一个对象。在这种情况下,映射的互斥锁也应该是类静态的,并且只要以需要同步的方式使用映射,就应该锁定它。请记住,类静态成员的初始化不是线程安全的。
function local static:
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中,则会得到一个对象。如果它位于标题内,则每个包含该标题的翻译单元都会获得一个对象。该对象的互斥锁也应该是转换单元静态,因为您需要与对象一样多的互斥锁。但是,我不建议在多线程环境中使用这种静态变量。
答案 2 :(得分:-1)
首先,您应该考虑在static
上阅读smth(也许请尝试this)。那是因为static
的含义取决于背景。
但这可能是一个并发症,我相信你有这样的事情:
class A {
private:
static std::map....
public:
void doSomethingWithMap() {
//lock mutex
//some action with map
//unlock mutex
}
}
如果是这种情况,那么您可能希望将您的互斥锁作为此类的成员。这就是重点 - 这取决于您需要的范围。如果你需要在这个类的所有对象中全局锁定 - 你应该考虑使用静态类成员,如果你想对每个对象进行锁定 - 你应该只使用一个类成员。
答案 3 :(得分:-2)
不,通常你不需要静态锁。