尝试创建线程的问题
Issue with trying to create a thread
我正在尝试创建一个函数,该函数接受一个 std::function
和一个值向量,并将 return 一个包含这些值的函数输出的向量,并利用线程为了加快速度。
当我编译我的代码时,它说它无法为 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,3,2,4 };
std::vector<int> summed_nums = thread_map(std::function<int(int)>(multiply_by_2), nums_to_sum, 12);
}
根据 cppreference std::thread
:
The arguments to the thread function are moved or copied by value. If
a reference argument needs to be passed to the thread function, it has
to be wrapped (e.g., with std::ref
or 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,它是 9 的约数,会更好。还要记住,创建线程的成本相对较高,您不想创建太多。 std::thread::hardware_concurrency() 将 return 您的系统支持的并发线程数。
我正在尝试创建一个函数,该函数接受一个 std::function
和一个值向量,并将 return 一个包含这些值的函数输出的向量,并利用线程为了加快速度。
当我编译我的代码时,它说它无法为 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,3,2,4 };
std::vector<int> summed_nums = thread_map(std::function<int(int)>(multiply_by_2), nums_to_sum, 12);
}
根据 cppreference std::thread
:
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g., with
std::ref
orstd::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,它是 9 的约数,会更好。还要记住,创建线程的成本相对较高,您不想创建太多。 std::thread::hardware_concurrency() 将 return 您的系统支持的并发线程数。