将向量传递给C++中的线程函数

Posted

技术标签:

【中文标题】将向量传递给C++中的线程函数【英文标题】:Passing vector to a thread function in c++ 【发布时间】:2015-09-04 19:15:26 【问题描述】:

我正在尝试运行一个多线程矩阵求和函数,以便每一行将在不同的线程中求和。我已经尝试在模板类中实现将向量传递给 cpp 线程函数的所有解决方法,但我仍然遇到这个常见错误。

代码:

template <typename T> class Matrix

    // variables for matrix size and variables in a one dimension vector
    unsigned int _rows;
    unsigned int _cols;
    vector<vector<T> > _matrix;

    // Matrix template class functions declarations (all common operators and constructors)

    void sumLine(vector<T>& first, vector<T>& second, vector<T>& result);
    Matrix<T> operator+(const Matrix<T> & other) const;
;

 // Matrix template class functions implmentations

template <typename T> void Matrix<T>::sumLine(vector<T>& first, vector<T>& second, vector<T>& result)

    for (unsigned int colIdx = 0; colIdx < _cols; colIdx++)
    
        result[colIdx] = first[colIdx] + second[colIdx];
    


template <typename T> Matrix<T> Matrix<T>::operator+(const Matrix<T> & other) const

    vector<thread> threads;
    vector<vector<T> > results;
    vector<T> newRow(_cols);
    results.resize(_rows, newRow);
    for (unsigned int rowIdx = 0; rowIdx < _rows; rowIdx++)
    
        vector<T> first = _matrix[rowIdx];
        vector<T> second = other._matrix[rowIdx];
        vector<T> result = results[rowIdx];
        threads.push_back(thread(Matrix<T>::sumLine, std::ref(first), std::ref(second), std::ref(result)));
    
    for (unsigned int thrdIdx = 0; thrdIdx < _rows; thrdIdx++)
    
        threads[thrdIdx].join();
    

    // do something with vector<vector<T>> results

在使用 gcc 编译后我仍然得到:

    In file included from /usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/thread:39:0,
                 from Matrix.hpp:12,
                 from main.cpp:13:
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/functional: In instantiation of 'struct std::_Bind_simple<std::_Mem_fn<void (Matrix<Complex>::*)(std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&)>(std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >)>':
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/thread:137:47:   required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (Matrix<Complex>::*)(std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&); _Args = std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >]'
Matrix.hpp:404:102:   required from 'Matrix<T> Matrix<T>::operator+(const Matrix<T>&) const [with T = Complex]'
main.cpp:59:14:   required from here
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/functional:1665:61: error: no type named 'type' in 'class std::result_of<std::_Mem_fn<void (Matrix<Complex>::*)(std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&)>(std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >)>'
       typedef typename result_of<_Callable(_Args...)>::type result_type;
                                                             ^
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/functional:1695:9: error: no type named 'type' in 'class std::result_of<std::_Mem_fn<void (Matrix<Complex>::*)(std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&, std::vector<Complex, std::allocator<Complex> >&)>(std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >, std::reference_wrapper<std::vector<Complex, std::allocator<Complex> > >)>'
         _M_invoke(_Index_tuple<_Indices...>)

当 Complex 是我为矩阵模板类编写的复数类时,我的主要功能是尝试将这个计算与它一起使用。这里有什么问题?如果是在复杂类中,有没有更简单的方法给线程函数传递参数来避免这种情况?

【问题讨论】:

除了错误之外,您的代码(如预期的那样)也是错误且效率低下的。例如,在启动线程之前分配结果矩阵的所有行并初始化其所有元素是串行的(相反,这可能是并行代码的一部分)。此外,我会emplace_back 每个线程(而不是push_back)。最后(正如已经在答案中指出的那样),您的代码实际上并没有计算结果矩阵,因为每个结果行都被写入局部变量,然后被丢弃......) 【参考方案1】:

您应该发布您的 Complex 类,这可能是问题所在。

也在您的代码中: vector<T> first = _matrix[rowIdx]; vector<T> second = other._matrix[rowIdx]; vector<T> result = results[rowIdx];

你应该这样写:vector&lt;T&gt;&amp; first = _matrix[rowIdx];

因为您正在复制这些向量……如果您不修改它们,甚至是 const vector&lt;T&gt;&amp; first = _matrix[rowIdx];

然后你可以删除 std::ref

【讨论】:

【参考方案2】:

以下代码编译(使用 clang 3.5)并避免将对临时对象的引用传递给任何 thread ...

#include <vector>
#include <thread>
#include <stdexcept>

using namespace std;         // for expose only (don't do this in real code!!)
template <typename T> class Matrix

  using row = vector<T>;
  size_t _rows, _cols;
  vector<row> _matrix;
  Matrix(vector<row>&&); // defined elsewhere

  row sumLine(row const& first, row const& second) const
  
    row result;                          // don't tempt the compiler to default
    result.reserve(_cols);               // initialise result[i] for all columns
    for(size_t c=0; c!=_cols; ++c)
      result.emplace_back(first[c]+second[c]);
    return result;                       // return is fast (no copy!)
  

  Matrix<T> operator+ (const Matrix<T>& other) const;
;

template <typename T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>&other) const

  if(other._cols != _cols)
    throw std::runtime_error("column number mismatch in Matrix+Matrix");
  if(other._rows != _rows)
    throw std::runtime_error("row number mismatch in Matrix+Matrix");
  vector<thread> threads; threads.reserve(_rows);
  vector<row> result(_rows);
  for(size_t r=0; r!=_rows; ++r)
    threads.emplace_back([&,r]() 
        result[r] = Matrix<T>::sumLine(_matrix[r],other._matrix[r]);
      );
  for(size_t r=0; r!=_rows; ++r)
    threads[r].join();
  return move(result);


template class Matrix<double>;

【讨论】:

以上是关于将向量传递给C++中的线程函数的主要内容,如果未能解决你的问题,请参考以下文章

C ++将多个对象传递给线程中的函数

c++中如何将子线程的参数传回主线程

将派生类指针的向量传递给线程

C++ 将向量传递给重载类 - 有些调用语句有效,有些则无效。

将指针向量传递给c ++中的函数[重复]

在函数中传递向量元素[关闭]