這裏有兩個問題:
將互斥正確創建?
互斥體的使用是否正確?
由於問題的答案是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在這兩種情況下都是共享資源,如果要在創建後更改,它也應該受互斥鎖保護。然而,這樣的鎖可以(正確地)銷燬所有的並行性,所以我們暫時忽略它;)
無論它是否工作,都取決於您是否正確使用互斥鎖。但有一點是肯定的:如果你不明白你的互斥體和/或互斥體指針發生了什麼,你可能會遇到一些麻煩。 – 2012-02-16 23:19:44