如何 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;
这允许您解决编译错误。
我正在尝试使用互斥锁来防止多个线程同时读取变量。
我的代码生成多个 "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;
这允许您解决编译错误。