将数组作为引用传递给线程

3

我有一个数组需要传递给多个线程进行处理。数组大小在编译时已知。 这里是一个简化的示例,其中函数直接被调用,而不是通过线程:

#include <thread>

template <class TYPE>
void function(TYPE& data, std::size_t row, std::size_t column){
    data[row-1][column-1]=2;
}

int main(){
    const int column(5),row(2);
    std::array<std::array<int, column>, row> arr;
    function(arr, row, column);
    return data[row-1][column-1];
}

代码按预期返回2。 如果我通过调用函数
    std::thread worker(function<std::array<std::array<int,column>,row>>, arr, row, column);

我收到了以下编译器错误信息:

g++ Testo.cpp -o Testo -std=c++11 -lpthread
In file included from /usr/include/c++/4.8/thread:39:0,
                 from Testo.cpp:2:
/usr/include/c++/4.8/functional: In instantiation of ‘struct std::_Bind_simple<void (*(std::array<std::array<int, 5ul>, 4ul>, int, int))(std::array<std::array<int, 5ul>, 4ul>&, long unsigned int, long unsigned int)>’:
/usr/include/c++/4.8/thread:137:47:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(std::array<std::array<int, 5ul>, 4ul>&, long unsigned int, long unsigned int); _Args = {std::array<std::array<int, 5ul>, 4ul>&, const int&, const int&}]’
Testo.cpp:13:82:   required from here
/usr/include/c++/4.8/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<void (*(std::array<std::array<int, 5ul>, 4ul>, int, int))(std::array<std::array<int, 5ul>, 4ul>&, long unsigned int, long unsigned int)>’
       typedef typename result_of<_Callable(_Args...)>::type result_type;
                                                             ^
/usr/include/c++/4.8/functional:1727:9: error: no type named ‘type’ in ‘class std::result_of<void (*(std::array<std::array<int, 5ul>, 4ul>, int, int))(std::array<std::array<int, 5ul>, 4ul>&, long unsigned int, long unsigned int)>’
         _M_invoke(_Index_tuple<_Indices...>)
         ^

我可以更改我的模板为:
template <class TYPE>
void function(TYPE data, std::size_t row, std::size_t column){
    data[row-1][column-1]=2;
}

现在编译器已不再报错,但由于数组不再通过引用传递,因此主函数返回0。 那么线程的正确模板首个参数是什么,以便像直接调用函数一样通过引用传递数组?


arr在你使用它之后才被声明在function中,那么它应该如何工作呢? - crashmstr
你的第一个代码片段无法编译,因为arr在函数调用之后定义。 - NathanOliver
抱歉,我之前粘贴了那行代码。谢谢,现在已经修复了。 - Kartoffelpelz
2个回答

7

你的函数期望一个数组的引用,但是 std::thread 存储了已衰变的绑定参数的副本。数组转指针衰变会导致指针类型的 prvalue . 为了解决这个问题,通过 std::reference_wrapper 传递 arr 来保留类型:

std::thread worker(..., std::ref(arr), row, column);

您也可以使用lambda,这样您就不必显式传递模板参数:

std::thread worker([&arr]{ return function(arr, row, column); });

感谢您的解释。在代码中,真正的函数只被调用了两次,并且有超过20个参数,因此在这种特定情况下,使用lambda并不能减少维护工作。但是我将来一定会在其他应用中使用它。 - Kartoffelpelz
如果你要使用lambda,最好在lambda中捕获参数而不是通过线程构造函数传递它们。这样做既简单又避免了像OP那样的问题:std::thread worker([&arr]{ return function(arr, row, column); });。(注意,rowcolumn不需要被捕获:它们是常量,立即应用左值到右值转换,因此不会被lambda ODR使用。) - Casey

2

按引用传递 std::ref(arr)


谢谢,解决了问题!等7分钟后我会标记为已回答。 - Kartoffelpelz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接