问题描述
我正在尝试制作一个接受std::function
和值向量的函数,并将返回一个包含这些值输出的函数的向量,并利用线程来加快速度。
当我编译代码时,它说它无法专用于std::invoke
的函数模板,并且它期望有1个参数并得到7
这是我的代码:
#include <vector>
#include <thread>
#include <functional>
#include <iterator>
template<
typename RETURN,typename INPUT
>
void thread_instance(std::function<RETURN(INPUT)> function,const std::vector<INPUT>& input,typename std::vector<INPUT>::iterator input_start,typename std::vector<INPUT>::iterator input_end,std::vector<RETURN>& output,typename std::vector<RETURN>::iterator output_start)
{
for (; input_start != input_end; ++input_start,++output_start)
{
*output_start = function(*input_start);
}
}
template<
typename RETURN,typename INPUT
>
std::vector<RETURN> thread_map(std::function<RETURN(INPUT)> function,std::vector<INPUT> input,int thread_count)
{
std::vector<std::thread> threads(thread_count);
std::vector<RETURN> output(input.size());
for (int i = 0; i < thread_count; ++i)
{
int start_index = (input.size() / thread_count) * i;
int end_index = start_index + input.size() / thread_count;
typename std::vector<INPUT>::iterator thread_input_start = input.begin() + start_index;
typename std::vector<INPUT>::iterator thread_input_end = input.begin() + end_index;
typename std::vector<RETURN>::iterator thread_output_start = output.begin() + start_index;
threads[i] = std::thread(thread_instance<RETURN,INPUT>,function,input,thread_input_start,thread_input_end,output,thread_output_start);
}
for (int i = 0; i < thread_count; ++i)
{
threads[i].join();
}
return output;
}
int multiply_by_2(int num)
{
return num * 2;
}
int main(int argc,char** argv)
{
std::vector<int> nums_to_sum = { 4,3,67,5,32,6,2,4 };
std::vector<int> summed_nums = thread_map(std::function<int(int)>(multiply_by_2),nums_to_sum,12);
}
解决方法
根据std::thread
的{{3}}:
线程函数的参数按值移动或复制。如果 一个引用参数需要传递给线程函数,它具有 进行包装(例如,用
std::ref
或std::cref
包装)。
想一想,如果使用引用启动线程并且线程启动后对象被销毁,会发生什么?悬挂的参考和不确定的行为!因此,按值接受参数的默认行为是有道理的。
在您的情况下,您甚至没有使用输出向量。输出向量的迭代器就足够了,并且可以按值传递。因此,我建议更改您的函数,使其不通过引用接受输出向量:
template<
typename RETURN,typename INPUT
>
void thread_instance(std::function<RETURN(INPUT)> function,const std::vector<INPUT>& input,typename std::vector<INPUT>::iterator input_start,typename std::vector<INPUT>::iterator input_end,typename std::vector<RETURN>::iterator output_start)
{
for (; input_start != input_end; ++input_start,++output_start)
{
*output_start = function(*input_start);
}
}
另一件事是,如果要使用整数除法计算起始迭代器,则如下所示:
int start_index = (input.size() / thread_count) * i;
并且thread_count
大于input.size()
的结果将始终为零。用12以外的数字代替3是更好的选择,例如3。还请记住,创建线程是相对昂贵的,并且您不想创建太多线程。 cppreference将返回系统支持的并发线程数。