2012-02-14 96 views
3

我想了解如何在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附加一个互斥锁,并(例如)调用std :: lock_guard。但是,如果我取消对互斥量的注释,那么对于赋值和复制操作符,我会遇到一堆关于“使用已删除函数”的编译器错误。我在安全锁定对象的目标中缺少什么?

回答

6

直截了当的方法,使一类线程是在存取方法

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; 
    } 
}; 

然而,这意味着,当任何其他实例正在访问类块的每个实例,因为他们都有着相同的互斥。

从理论上讲,可以通过手动编写复制构造函数和赋值运算符来使包含非静态互斥锁的类成为可复制的,从而省去互斥锁。但是,要做到这一点很困难且乏味,特别是对于在开发过程中经常更改的具有大量属性的类而言。

如果一个静态互斥锁阻止对类的所有实例进行阻塞时的访问是不可接受的,那么最好和最简单的方法就是将互斥锁维持在类之外。以这种方式公开类的内部工作可能看起来不幸,但替代方式更复杂,因此不可靠,并且当访问类的代码级别处理互斥锁时,我经常发现重要的优化。

+0

@MikeSeymour除非我误解了他在说什么,否则他需要在所有线程中使用**相同的**互斥体。使用移动语义把它放在容器中是行不通的。 (另一方面,正如目前所写,每个线程都有自己的'Rope'对象,所以不需要互斥体。当问题没有被明确解释时,很难说正确的解决方案。) – 2012-02-14 17:42:43

+0

@ Mike Seymour:'std :: mutex'不可移动。我们可以使'Rope'在每个'Rope'构造函数中默认构造'std :: mutex'来移动或者复制。或者通过让詹姆斯暗示的互斥体是静态的。这两种方法中的哪一种是合适的,只有OP在此时才知道。 – 2012-02-14 20:17:12

+0

我的错误;在发布之前,我应该检查我的假设。 – 2012-02-15 07:03:13

0

您错过了mutex不可复制的事实。 代表一个互斥体的副本是什么意思?获取和释放互斥锁 的地方在Rope::compute中,并且由于所有线程都必须访问 相同的互斥锁,因此您必须在runTest中将其定义并通过 引用或通过指针传入。