当在不同的索引上写入时,这个矩阵类线程安全吗?
Is this matrix class thread safe when writing on different indices?
您可能注意到这后面有一个双*存储。任何读/写的值都被转换成一个平面索引,因此它被存储在一个大的一维数组中。
我需要知道我是否可以在不同线程中对该类型对象的不同索引进行写入?我使用运算符()来设置值。边界是在实例化对象时预定义的。即:矩阵m(行,cols);我在boost线程中使用这个并有问题。我需要放置任何作用域锁吗?但我相信那将是性能上的损失。
class matrix
{
public:
matrix(size_t rows, size_t cols):_rows(rows),_cols(cols),_data(0)
{
reset(rows, cols);
}
matrix():_data(0),_rows(0),_cols(0){}
~matrix()
{
if (0 != _data)
{
delete [] _data;
}
}
matrix(const matrix& copythis)
:_data(0),_rows(0),_cols(0)
{
if (0 != _data)
{
delete [] _data;
}
_rows = copythis.rows();
_cols = copythis.cols();
_data = new double [_rows * _cols];
if (0 == _data)
{
NL_THROW("Insufficient memory to create a cloned matrix of double of " << _rows << " X " << _cols);
}
memcpy(_data, copythis._data, _rows * _cols * sizeof(double) );
}
public:
const matrix& operator = (const matrix& copythis)
{
if (0 != _data)
{
delete [] _data;
}
_rows = copythis.rows();
_cols = copythis.cols();
_data = new double [_rows * _cols];
if (0 == _data)
{
NL_THROW("Insufficient memory to create a cloned matrix of double of " << _rows << " X " << _cols);
}
memcpy(_data, copythis._data, _rows * _cols * sizeof(double) );
return (*this);
}
double* cArray()
{
if (0 == _data)
{
NL_THROW("Matrix is not initialised");
}
return _data;
}
void reset(size_t rows, size_t cols)
{
if (0 != _data)
{
delete [] _data;
}
_rows = rows;
_cols = cols;
_data = new double[rows * cols];
if (0 == _data)
{
NL_THROW("Insufficient memory to create a matrix of double of " << _rows << " X " << _cols);
}
memset(_data, 0, sizeof(double) * _rows * _cols);
}
double& operator () (size_t rowIndex, size_t colIndex) const
{
if (rowIndex >= _rows)
{
NL_THROW("Row index " << rowIndex << " out of range(" << _rows - 1 << ")");
}
if (colIndex >= _cols)
{
NL_THROW("Column index " << colIndex << " out of range(" << _cols - 1 << ")");
}
size_t flatIndex = colIndex + rowIndex * _cols;
return _data[flatIndex];
}
Array rowSlice(size_t rowIndex) const
{
if (rowIndex >= _rows)
{
NL_THROW("Cannot slice matrix, required row: " << rowIndex << " is out of range(" << (_rows - 1) << ")");
}
Array retval(_data + rowIndex * _cols, _cols);
/*
for(size_t i = 0; i < _cols; i++)
{
retval[i] = operator()(rowIndex, i);
}
*/
return retval;
}
Array colSlice(size_t colIndex) const
{
if (colIndex >= _cols)
{
NL_THROW("Cannot slice matrix, required row: " << colIndex << " is out of range(" << (_cols - 1) << ")");
}
Array retval(_rows);
for(size_t i = 0; i < _rows; i++)
{
retval[i] = operator()(i, colIndex);
}
return retval;
}
void fill(double value)
{
for(size_t rowIndex = 0; rowIndex < _rows; rowIndex++)
{
for(size_t colIndex = 0; colIndex < _cols; colIndex++)
{
size_t flatIndex = colIndex + rowIndex * _cols;
_data[flatIndex] = value;
}
}
}
bool isEmpty() const
{
if (0 == _rows) return true;
if (0 == _cols) return true;
return false;
}
size_t rows() const {return _rows;}
size_t cols() const {return _cols;}
private:
double* _data;
size_t _rows;
size_t _cols;
};
如果您能保证所有的线程永远不会在矩阵的同一元素上发生冲突,那么您就不需要锁定。在实践中,期望这样的保证是不现实的,因此需要锁定。
这个类的编写方式,除了getter rows()
和cols()
,您需要在上锁定每个方法,几乎在每个方法上尽可能广泛的范围。
您甚至不能依赖于size_t
类型是原子的,因为reset()
以非原子的方式设置_row
和_col
。任何需要知道_row
和_col
的操作,例如isEmpty()
,如果从另一个线程调用reset()
,将会遇到麻烦。
相关文章:
- 如何将元素添加到数组的线程安全函数?
- C++中的线程安全删除
- 在std::thread中,joinable()然后join()线程安全吗
- 在c++队列中使用pop和visit实现线程安全
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 全局变量 多读取器 一个写入器多线程安全?
- 共享队列的线程安全
- boost::文件系统::recursive_directory_iterator多线程安全
- 以线程安全的方式转换 C/C++ 中时区名称字符串的时区偏移量
- 线程安全运算符<<
- 如何使缓存线程安全
- C++线程安全:如果只有一个线程可以写入非原子变量,但多个线程从中读取. 会遇到问题吗?
- 提升精神 V2 Qi 语法线程安全吗?
- asio 链对象线程安全吗?
- 线程安全队列 c++
- 提供对不同类型的数据(建议、代码审查)的线程安全访问的类
- 如何以线程安全的方式更改目录?
- 线程安全的引用计数队列C++
- 析构函数和线程安全
- 适用于大型数组的无复制线程安全环形缓冲区