c++ - 如何修复: Executing lambda expression using pthread in c++

标签 c++ lambda pthreads

我有一个 main.cpp 文件,其中包含以下代码

paral(start, end, [&](int i){
    C1[i] = A1[i] + B[i];
}, numThreads);`

我在 otherfile.cpp 中有 paral 定义,其中有以下代码

void paral(int start, int end, T &&lambda, int nT){
    pthread_t thread1;
    int status = pthread_create(&thread1, NULL,lambda ,1);//Should execute lambda(1)
    lambda(2);//Executed by main thread
    //Code for join and so on
}

它说:

can't covert lambda to (void*)(*)(void *).

我尝试将 lambda 函数强制转换并传递给 pthread,但这没有帮助。 我也想从创建的线程调用 lambda 函数,但我无法做到。

最佳答案

首先您必须了解 Lambda 是一个对象,它实现 operator()(args...) 成员函数。在您的具体情况下,它是operator()(int i)

为了执行此 lambda,必须将两个参数传递给 operator()(int):

  • Lambda 指针(this)
  • 整数

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 缓存。

另请参阅:

关于c++ - 如何修复: Executing lambda expression using pthread in c++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54069445/

相关文章:

c++ - errno 在不同系统上的位置

c++ - 如何将 STL 算法的 lambdas 绑定(bind)到 C 风格的多维数组?

java - 将对象属性列表加入字符串

c++ - 将所有参数移至 lambda

c - 为什么这个多线程程序可以工作(而不是崩溃)?

c++ - QT:如何同时打开多个窗口(QWidgets)?

c++ - 我的 findContours() 函数在具有不同 dpi 的图像上表现异常

c++ - Gtkmm 程序编译正常但崩溃 - Windows XP

function - 为什么不能将变量移出闭包?

c - pthread_cleanup_pop 参数为 0?