首先你要明白Lambda是一个对象,它实现了operator()(args...)成员函数。在您的具体情况下,它是operator()(int i)。
为了执行这个 lambda,必须将两个参数传递给 operator()(int):
lambda 的地址是对象(即数据)的地址,而不是代码的地址。
线程启动函数是一个接受void* 并返回void* 的函数。函数地址是机器码的地址。
因此,要执行您的 lambda,您应该定义 void* (void*) 函数并将其地址作为 start_routine 参数传递。你作为arg参数传递的lambda的地址:
template<typename Lambda>
void paral(int start, int end, Lambda&& lambda, int nT){
struct Args
{
int Start;
int End;
Lambda& Func;
};
// create captureless lambda
auto threadStart = +[](void* voidArgs) -> void*
{
auto& args = *static_cast<Args*>(voidArgs);
for(int i = args.Start; i < args.End; ++i)
args.Func(i);
return nullptr;
};
// I create one thread here. You will create more.
auto args = Args{start, end, lambda};
pthread_t handle;
int rc = pthread_create(&handle, NULL, threadStart, &args);
if(rc)
throw std::system_error(
std::error_code(rc, std::generic_category()),
"pthread_create");
pthread_join(handle, nullptr);
}
但是在这种特定情况下,您最好使用std::thread 而不是pthread 库。在这种情况下,您的代码可能如下所示:
#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
template<typename Func>
void paral(int start,
int end,
Func &&func,
int threads_count = std::thread::hardware_concurrency())
{
std::atomic_int counter {start};
std::vector<std::thread> workers;
workers.reserve(threads_count);
for(int i = 0; i < threads_count; ++i) {
workers.emplace_back([end, &counter, &func] {
for(int val = counter++; val < end; val = counter++)
func(val);
});
}
for(int i = 0; i < threads_count; ++i)
workers[i].join();
}
int main() {
int C1[10];
int A[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int B[10] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 110};
paral(0, 10, [&](int i){ C1[i] = A[i] + B[i]; });
for(auto&& v: C1)
std::cout << v << "\n";
std::cout << "Done. Bye!" << std::endl;
}
不过有重要提示。您的代码可能没有您预期的那么快。它将遇到false sharing 问题,因为多个线程修改同一缓存行的内存,这将迫使 CPU 内核每次在另一个 CPU 内核更新内存时更新其 L1 缓存。
另见: