如何 copy/move 包含互斥量的 class

How to copy/move a class containing a mutex

我正在尝试使用互斥锁来防止多个线程同时读取变量。

我的代码生成多个 "Carriers" 对象,它们都具有相同的 "SMSDetector" 并且在尝试评估某些 Dolfin 函数时代码崩溃(分段错误)(是的,我使用 Fenics 库进行某些 FEM 计算) ;所以我试图在求值前锁定互斥锁,然后再解锁。

我现在的问题是,我需要 copy/move 构造函数来使 Carrier class 成为 mov/copi-able,但我似乎没有弄对它们。没有互斥锁我得到:Carrier.cpp:203:42: error: ‘Carrier& operator=(const Carrier&)’ must be a nonstatic member function Carrier& operator = (const Carrier& other)

使用互斥量我得到:Carrier.cpp:200:49: error: no matching function for call to ‘std::lock_guard<std::mutex>::lock_guard(const std::mutex&)’ std::lock_guard<std::mutex> lock(other.safeRead);

我正在尝试用 c++11 标准编写整个程序,所以如果有人有 c++11 解决方案,我将不胜感激。

这是有冲突的代码:

std::valarray<double> Carrier::simulate_drift(double dt, double max_time, double x_init, double y_init )

{
      _x[0] = x_init;
      _x[1] = y_init;

      // get number of steps from time
  int max_steps = (int) std::floor(max_time / dt);

  std::valarray<double>  i_n(max_steps); // valarray to save intensity

  runge_kutta4<std::array< double,2>> stepper;

  // wrapper for the arrays using dolphin array class
  Array<double> wrap_x(2, _x.data());
  Array<double> wrap_e_field(2, _e_field.data());
  Array<double> wrap_w_field(2, _w_field.data());

  double t=0.0; // Start at time = 0

  for ( int i = 0 ; i < max_steps; i++)
  {

    if (t < _gen_time) // If CC not yet generated
    {   
      i_n[i] = 0;
    }   
    else if (_detector->is_out(_x)) // If CC outside detector
    {   
      i_n[i] = 0;
      break; // Finish (CC gone out)
    }   
    else
    {   
      safeRead.lock();
      _detector->get_d_f_grad()->eval(wrap_e_field, wrap_x);
      _detector->get_w_f_grad()->eval(wrap_w_field, wrap_x);
      safeRead.unlock();
      _e_field_mod = sqrt(_e_field[0]*_e_field[0] + _e_field[1]*_e_field[1]);
      i_n[i] = _q *_sign* _mu.obtain_mobility(_e_field_mod) * (_e_field[0]*_w_field[0] + _e_field[1]*_w_field[1]);
      stepper.do_step(_drift, _x, t, dt);
      // Trapping effects due to radiation-induced defects (traps) implemented in CarrierColleciton.cpp
    }   
    t+=dt;
  }
    return i_n;
}
/*
 * Copy initialization
 */
Carrier::Carrier(const Carrier& other)
{
  _carrier_type = other._carrier_type;
    _q = other._q;
    _gen_time = other._gen_time;
    _x = other._x; 
    _e_field = other._e_field; 
    _w_field = other._w_field;
    _e_field_mod = other._e_field_mod;
    _sign = other._sign; 
    _detector = other._detector;
    _myTemp = other._myTemp;
    _drift = other._drift;
    _mu = other._mu;
    _trapping_time = other._trapping_time;
    std::lock_guard<std::mutex> lock(other.safeRead);
}

/*
 * Copy assignment
 */
Carrier& operator = (const Carrier& other) 
{
//  std::lock(safeRead, other.safeRead;
//  std::lock_guard<std::mutex> self_lock(safeRead, std::adopt_lock;
//  std::lock_guard<std::mutex> other_lock(other.safeRead, std::adopt_lock;
    std::lock_guard<std::mutex> self_lock(safeRead, std::adopt_lock);
    std::lock_guard<std::mutex> other_lock(other.safeRead, std::adopt_lock);
  _carrier_type = other._carrier_type;
    _q = other._q;
    _gen_time = other._gen_time;
    _x = other._x; 
    _e_field = other._e_field; 
    _w_field = other._w_field;
    _e_field_mod = other._e_field_mod;
    _sign = other._sign; 
    _detector = other._detector;
    _myTemp = other._myTemp;
    _drift = other._drift;
    _trapping_time = other._trapping_time;
    return *this;
}


/*
 * Move initialization
 */
Carrier::Carrier(Carrier&& other)
{
  _carrier_type = std::move(other._carrier_type);
    _q = std::move(other._q);
    _gen_time = std::move(other._gen_time);
    _x = std::move(other._x); 
    _e_field = std::move(other._e_field); 
    _w_field = std::move(other._w_field);
    _e_field_mod = std::move(other._e_field_mod);
    _sign = std::move(other._sign); 
    _detector = std::move(other._detector);
    _myTemp = std::move(other._myTemp);
    _drift = std::move(other._drift);
    _mu = std::move(other._mu);
    _trapping_time = std::move(other._trapping_time);
    std::lock_guard<std::mutex> lock(other.safeRead);
}

/*
 * Move assignment
 */
Carrier& operator = ( Carrier&& other) 
{
    std::lock(safeRead, other.safeRead);
    std::lock_guard<std::mutex> self_lock(safeRead, std::adopt_lock);
    std::lock_guard<std::mutex> other_lock(other.safeRead, std::adopt_lock);
  _carrier_type = std::move(other._carrier_type);
    other._carrier_type = NULL;
    _q = std::move(other._q);
    other._q = 0;
    _gen_time = std::move(other._gen_time);
    other._gen_time = 0;
    _x = std::move(other._x); 
    other._x = {0,0};
    _e_field = std::move(other._e_field); 
    other._e_field = {0,0};
    _w_field = std::move(other._w_field);
    other._w_field = {0,0};
    _e_field_mod = std::move(other._e_field_mod);
    other._e_field_mod = 0;
    _sign = std::move(other._sign); 
    other._sign = 0;
    _detector = std::move(other._detector);
    other._detector = NULL;
    _myTemp = std::move(other._myTemp);
    other._myTemp = 0;
    _drift = std::move(other._drift);
    _mu = std::move(other._mu);
    _trapping_time = std::move(other._trapping_time);
    other._trapping_time = 1e300;
    return *this;
}

如果有帮助,我会上传更多代码,但我觉得这已经足够了。

在此先感谢您的帮助

编辑:Class 声明(完整头文件):

#ifndef CARRIER_H
#define CARRIER_H

#include  <valarray>
#include  <mutex>

#include <CarrierTransport.h>
#include <SMSDetector.h>

#ifndef Q_MOC_RUN  // See: https://bugreports.qt-project.org/browse/QTBUG-22829
#include <boost/numeric/odeint/stepper/runge_kutta4.hpp>
#endif

using namespace boost::numeric::odeint;

class Carrier
{
  private:
    char _carrier_type;
    double _q; // charge
    double _gen_time; // instant of generation of the carrier
    std::array< double,2> _x; // carrier position array
    std::array< double,2> _e_field; // electric field at the carrier position
    std::array< double,2> _w_field; // weighting field at the carrier positions
    double _e_field_mod;
    int _sign; // sign to describe if carrier moves in e field direction or opposite
//      std::mutex safeRead;

    SMSDetector * _detector;
    double _myTemp; // Temperature of the detector
    DriftTransport _drift;
    JacoboniMobility _mu;
    double _trapping_time;

  public:
    Carrier( char carrier_type, double q, double x_init, double y_init, SMSDetector * detector, double gen_time);
        Carrier(Carrier&& other); // Move declaration
        Carrier& operator = (Carrier&& other); // Move assignment
        Carrier(const Carrier& other); // Copy declaration
        Carrier& operator = (const Carrier& other); // Copy Assignment
        ~Carrier();

    char get_carrier_type();

    std::array< double,2> get_x();
    double get_q();

    std::valarray<double> simulate_drift( double dt, double max_time);
    std::valarray<double> simulate_drift(double dt, double max_time, double x_init, double y_init );
};

#endif // CARRIER_H

operator= 的实施中,您需要指定 class 名称:

Carrier& Carrier::operator = (const Carrier& other)

您在锁定互斥体时遇到了您描述的编译错误,因为 std::mutex::lock() 不是 const 方法。在赋值运算符中,您可以通过 const 引用获取 other 参数,这是您应该做的。因此,它试图在 const 对象上调用非 const 函数,导致编译错误。

解决方法是在 Carrier class:

的声明中将成员声明为 mutable

mutable std::mutex safeRead;

这允许您解决编译错误。