我正在尝试理解如何在c++中对对象使用互斥锁。我有以下(微不足道的)多线程代码,我正在使用它作为速度测试:
struct Rope{
int n, steps, offset;
//std::mutex mut;
Rope() {}
Rope(int n, int steps, int offset) : n(n), steps(steps), offset(offset) {}
void compute(){
double a[n];
for (int i=0; i<n; i++)
a[i] = i + offset;
for (int step=0; step<steps; step++)
for (int i=0; i<n; i++)
a[i] = sin(a[i]);
}
};
void runTest(){
int numRuns = 30;
int n = 10000;
int steps = 10000;
std::vector<Rope> ropes;
std::vector<std::thread> threads;
for (int i=0; i<numRuns; i++)
ropes.push_back(Rope(n, steps, i));
for (auto& r : ropes)
threads.push_back(std::thread(&Rope::compute, r));
for (std::thread& t : threads)
t.join();
} 代码按原样运行得很好,并且在我的4核机器上有大约4倍的加速。当然,我没有在Rope中存储任何东西,所以不需要互斥。如果我现在假设我确实有一些需要保护的数据,我想在Rope上附加一个互斥锁(例如)在compute()循环中调用std::lock_guard。但是,如果我取消对互斥锁的注释,我会得到一堆关于赋值和复制运算符的“使用已删除函数”的编译器错误。在我的安全锁定对象的目标中,我错过了什么?
发布于 2012-02-15 01:29:50
创建threadsafe类的直接方法是添加一个互斥锁属性,并在访问器方法中锁定互斥锁
class cMyClass {
boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};问题是,这使得类是不可复制的。这一点很重要,特别是当您想要将类的对象存储在容器中时。
我可以通过将互斥锁设置为静态对象来使其正常工作。
class cMyClass {
static boost::mutex myMutex;
cSomeClass A;
public:
cSomeClass getA() {
boost::mutex::scoped_lock lock( myMutex );
return A;
}
};但是,这意味着当访问任何其他实例时,类的每个实例都会阻塞,因为它们都共享相同的互斥。
从理论上讲,包含非静态互斥锁的类可以通过手动编写复制构造函数和赋值操作符来使其可复制,从而省略互斥锁。但是,这很难做得很好,而且很乏味,特别是对于具有大量在开发过程中频繁更改的属性的类。
如果一个静态互斥锁在一个实例被阻塞时阻止对类的所有实例的访问是不可接受的,那么最好也是最简单的方法是在类之外维护互斥锁。以这种方式暴露类的内部工作可能看起来很不幸,但替代方法要复杂得多,因此不可靠,而且当在访问类的代码级别处理互斥锁时,我经常发现有显著的优化。
发布于 2012-02-15 01:39:49
您忽略了一个事实,即mutex是不可复制的。复制一个互斥锁意味着什么?获取和释放互斥锁的位置在Rope::compute中,由于所有线程都必须访问同一互斥锁,因此必须在runTest中定义互斥锁并通过引用或指针传递它。
https://stackoverflow.com/questions/9281342
复制相似问题