【发布时间】:2014-06-14 23:28:08
【问题描述】:
假设我有一个类来表示一些名为 foo 的数据结构:
class foo{
public:
foo(){
attr01 = 0;
}
void f(){
attr01 += 5;
}
private:
int attr01;
};
class fooSingleThreadUserClass{
void usefoo(){
fooAttr.f();
}
foo fooAttr;
}
现在应该在软件构建的后期,我发现我需要多线程。我应该在 foo 中添加互斥锁吗?
class foo{
public:
foo(){
attr01 = 0;
}
void f(){
attr01Mutex.lock();
attr01 += 5;
attr01Mutex.unlock();
}
private:
int attr01;
std::mutex attr01Mutex;
};
class fooMultiThreadUserClass{
void usefoo(){
std::thread t1(&fooMultiThreadUserClass::useFooWorker, this);
std::thread t2(&fooMultiThreadUserClass::useFooWorker, this);
std::thread t3(&fooMultiThreadUserClass::useFooWorker, this);
std::thread t4(&fooMultiThreadUserClass::useFooWorker, this);
t1.join();
t2.join();
t3.join();
t4.join();
}
void useFooWorker(){
fooAttr.f();
}
foo fooAttr;
}
我知道 fooMultiThreadUserClass 现在可以在没有竞争的情况下以高性能运行 foo,但是 fooSingleThreadUserClass 会因为互斥量开销而降低性能吗?我很想知道。或者我应该出于并发目的从 foo 派生 fooCC,以便 fooSingleThreadUserClas 可以继续使用没有互斥锁的 foo,而 fooMultiThreadUserClass 使用带有互斥锁的 fooCC,如下所示
class fooCC : public foo{
public:
foo(){
attr01 = 0;
}
void f(){ // I assume that foo::f() is now a virtual function.
attr01Mutex.lock();
foo::f();
attr01Mutex.unlock();
}
private:
std::mutex attr01Mutex;
};
还假设编译器优化已经处理了虚拟调度。我想知道我应该使用继承还是简单地将互斥锁放在原始类中。
我已经搜索过 Stackoverflow,但我想我的问题有点太具体了。
编辑:请注意,不一定只有一个参数,问题是抽象的,带有 n 个参数的类。
【问题讨论】:
-
首先你应该使用
std::lock_guard来锁定你的互斥锁,并且可能还让你的互斥锁mutable。 -
如果只有一个
int,可以使用std::atomic_int。 -
无竞争的互斥锁通常很便宜。我会将它直接添加到类中,并且仅在遇到性能问题时进行优化(并且确信它是互斥体减慢了速度)。
-
真正的类不只有一个数据成员。确保对象始终处于一致状态,同步所有数据成员,永远不能在类本身中实现。它必须由客户端代码完成。把工作交给最不可能做对的程序员。线程很难,我们去购物吧。
-
@HansPassant,我不同意。在对象级别制作是最简单的方法。但是,所有操作数据的函数都应该有一个
std::lock_guard以确保它保持同步。碰巧您需要同步多个对象,在这种情况下,但必须在对象之外实现它会使它变得更加复杂(至少在我的实践中,同步一堆对象要困难得多,除非它们本身是另一个对象的一部分,该对象本身可以在每个公共函数的基础上同步。)
标签: c++ multithreading c++11 mutex