繁体   English   中英

与对象的互斥

[英]mutexes with objects

我试图了解如何在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并且(例如)在compute()循环中调用std :: lock_guard。 但是,如果我取消注释互斥锁,我会收到一堆关于“使用已删除函数”的编译器错误,用于赋值和复制运算符。 我在安全锁定物体的目标中缺少什么?

使类线程安全的直接方法是添加互斥锁属性并在访问器方法中锁定互斥锁

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

但是,这意味着当访问任何其他实例时,类的每个实例都会阻塞,因为它们都共享相同的互斥锁。

从理论上讲,包含非静态互斥锁的类可以通过手工编写复制构造函数和赋值运算符来复制,以便省略互斥锁。 但是,这样做很困难,也很繁琐,特别是对于在开发过程中经常更改的具有大量属性的类。

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

您错过了mutex不可复制的事实。 制作互斥锁的副本意味着什么? 获取和释放互斥锁的地方是在Rope::compute ,由于所有线程都必须访问相同的互斥锁,因此您必须在runTest定义它并通过引用或指针传递它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM