与对象互斥 [英] mutexes with objects

查看:153
本文介绍了与对象互斥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图理解如何使用互斥体与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 a [i] = i + offset;
for(int step = 0; step< steps; step ++)
for(int i = 0; i a [i] = sin(a [i]
}

};

void runTest(){
int numRuns = 30;
int n = 10000;
int steps = 10000;

std :: vector< Rope>绳索
std :: vector< std :: thread>线程;
for(int i = 0; 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倍速加速核心机。我当然不在绳子中存储任何东西,所以没有互斥体的需要。如果我现在假设我有一些我需要保护的数据,我想附加一个互斥体到绳索和(例如)调用std :: lock_guard在compute()循环。如果我取消注释互斥,但是,我得到一堆关于使用删除的函数的编译器错误的分配和复制操作符。

解决方案

使类线程安全的简单方法是添加一个mutex属性并在访问器方法中锁定互斥体

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

但是,这意味着当访问任何其他实例时,类的每个实例都会阻塞,



理论上,包含非静态互斥体的类可以通过手工编码复制构造函数和赋值运算符来进行复制,以便省略互斥。但是,这是很困难和繁琐的做正确,特别是对于一个类有大量的属性,在开发过程中经常改变。



如果一个静态互斥量阻止访问当一个块被阻塞时,该类的所有实例都是不可接受的,那么最好的和最简单的方法是在类外维护互斥体。看起来不幸的是,以这种方式暴露类的内部工作,但是替代方法更复杂,因此不可靠,并且当在访问类的代码级别处理互斥体时,我经常发现显着的优化。 p>

I'm trying to understand how to use mutexes with objects in c++. I have the following (trivial) multi-threaded code I'm using as a speed test:

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

The code runs fine as is, and sees a ~4x speedup on my 4 core machine. I am, of course, not storing anything in the Rope, so there is no need for a mutex. If I now presume that I did have some data I needed to protect, I'd like to attach a mutex to the Rope and (e.g.) call std::lock_guard within the compute() loop. If I uncomment the mutex, though, I get a bunch of compiler errors about "use of deleted function" for assignment and copy operators. What am I missing in my goal to safely lock an object?

解决方案

The straightforward way to make a class threadsafe is to add a mutex attribute and lock the mutex in the accessor methods

class cMyClass {
  boost::mutex myMutex;
  cSomeClass A;
public:
  cSomeClass getA() {
    boost::mutex::scoped_lock lock( myMutex );
    return A;
  }
};

The problem is that this makes the class non-copyable. This is important, especially if you want to store objects of the class in a container.

I can make things work by making the mutex a static.

class cMyClass {
  static boost::mutex myMutex;
  cSomeClass A;
public:
  cSomeClass getA() {
    boost::mutex::scoped_lock lock( myMutex );
    return A;
  }
};

However, this means that every instance of the class blocks when any other instance is being accessed, because they all share the same mutex.

Theoretically, a class containing a non-static mutex can be made copyable by hand coding the copy constructor and assignment operator so as to leave out the mutex. However, this is difficult and tedious to do properly, especially for a class with a large number of attributes that frequently change during development.

If a static mutex that blocks access to all instances of the class when one is blocked is not acceptable, then the best and simplest approach is to maintain the mutexes outside the class. It might seem unfortunate to expose the inner workings of a class in this way, but the alternatives are way more complex, hence unreliable, and I frequently find significant optimizations when the mutexes are handled at the level of the code accessing the class.

这篇关于与对象互斥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆