以下代码会给我一个错误,因为boost :: mutex是不可复制的,而xyz.push_back()是一个复制构造函数。
class XYZ
{
public:
double x;
boost::mutex x_mutex;
}
vector<XYZ> xyz;
xyz.push_back(XYZ());
所以我尝试过这样的事情,
class XYZ
{
public:
double x;
boost::mutex * x_mutex;
}
vector<XYZ> xyz;
xyz.push_back(XYZ());
它没有错误,但问题是“互斥体实际上是否会按原样运行?”这是在类中封装互斥体,然后创建该类的向量的好方法吗?
感谢。
答案 0 :(得分:6)
这里有两个问题:
是否可以正确创建互斥锁?
是否正确使用了互斥锁?
问题是1.答案是否定的。互斥锁指针未指向互斥锁。
因此,您需要添加适当的构造函数。 既然你需要一个构造函数,你可能需要实现一个析构函数,复制构造函数和赋值运算符,如果你希望你的类行为正确的话。
要么
XYZ::XYZ() : x(0), x_mutex(new boost::mutex) {}
XYZ::~XYZ() { delete x_mutex; }
XYZ::XYZ( const XYZ & xyz ) : x(xyz.x), x_mutex( new boost::mutex ) {}
XYZ& XYZ::operator=( const XYZ & xyz ) { x=xyz.x; }
或
explicit XYZ::XYZ( boost::mutex * m ) : x(0), x_mutex(m) {}
// Strictly speaking we dont need these as the default version does the right thing.
XYZ::~XYZ() {}
XYZ::XYZ( const XYZ & xyz ) : x(xyz.x), x_mutex( xyz.x_mutex ) {}
XYZ& XYZ::operator=( const XYZ & xyz ) { x=xyz.x; x_mutex = xyz.x_mutex; }
将是我所期待的。
在第一种情况下,对象的每个实例和副本都有自己的互斥锁。在第二个对象中,每个对象与其副本共享一个互斥锁,但必须在实例之前创建互斥锁。
还有第三种变体,其中互斥体可以由构造函数创建并与所有实例共享,但为此,您将shared_ptr
保存到互斥锁而不是原始指针。
class XYZ
{
public:
double x;
boost::shared_ptr<boost::mutex> x_mutex;
XYZ() : x(0), x_mutex( new boost::mutex ) {}
// Default versions of the other three do the right thing.
};
如果我们沿着这些路径走下去,我们最终会出现正确创建并初始化互斥锁的情况。
现在对于棘手的部分“是否正确使用互斥锁?”。要回答这个问题,我们需要知道线程之间如何共享对象,互斥锁应该保护的共享数据是什么。
如果在创建任何工作线程之前在主线程中创建了对象向量,并且每个对象实例都被工作线程修改(以便互斥锁真正保护x数据)那么第一个版本可能是正确的。在这种情况下,您的代码看起来更像是这样。
//Main thread
std::vector<XYZ> v;
for(unsigned int i=0; i<10; ++i)
v.push_back(XYZ());
//Several worker threads like this
j = rand()%10;
v[j].x_mutex->lock();
v[j].x+=1;
v[j].x_mutex->unlock();
如果x实际上是一个指针类型,并且它所指向的东西在线程之间共享,那么你的代码可能看起来像这样,并且要使用的代码的正确版本是2或3。
//Main thread
std::vector<XYZ> v;
X * xa;
boost::mutex xa_mutex;
X * xb;
boost::mutex xb_mutex;
for(unsigned int i=0; i<5; ++i)
v.push_back(XYZ(xa,xa_mutex));
for(unsigned int i=0; i<5; ++i)
v.push_back(XYZ(xb,xb_mutex));
//Several worker threads like this
j = rand()%10;
v[j].x_mutex->lock();
v[j].x->do_something();
v[j].x_mutex->unlock();
关键是每个共享资源都有一个互斥锁。
请注意,从技术上讲,向量v在两种情况下都是共享资源,如果要在创建后更改,还应该由互斥锁保护。然而,这样的锁会(正确地)破坏所有并行性。所以让我们暂时忽略它;)