【问题标题】:How do I pass a template function to a thread within the same .cpp file?如何将模板函数传递给同一 .cpp 文件中的线程?
【发布时间】:2021-07-30 06:17:20
【问题描述】:

我有一个任务是实现最长公共子序列算法的并行版本(仅计算 LCS 长度)。程序必须使用线程才能尽快完成任务(至少比顺序实现快)。理想情况下,它还应该在线程中使用 TLS。我们有一个类似的作业,在 .hpp 文件中实现了一个模板,我想使用相同的模板,但似乎我不能在这个作业中使用 .hpp 文件。我的问题在于将模板函数传递给我的线程。下面是代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include <unistd.h>
#include <chrono>
#include <thread>
#include <functional>


#ifdef __cplusplus
extern "C" {
#endif

  void generateLCS(char* X, int m, char* Y, int n);
  void checkLCS(char* X, int m, char* Y, int n, int result);

#ifdef __cplusplus
}
#endif


class ParFor {
public:
template<typename TLS>
  void parfor(size_t beg, size_t endm, size_t endn, size_t increment,
           std::function<void(TLS&)> before,
           std::function<void(int, int, TLS&)> f,
           std::function<void(TLS&)> after
           ) {
    TLS tls;
    before(tls);
    for (size_t a=beg; a<endm; a+= increment) {
      for (size_t b=beg; b<endn; b+= increment) {
        f(a, b, tls);
      }
    }
    after(tls);
  }
};


int main (int argc, char* argv[]) {

  if (argc < 4) { std::cerr<<"usage: "<<argv[0]<<" <m> <n> <nbthreads>"<<std::endl;
    return -1;
  }

  int m = atoi(argv[1]);
  int n = atoi(argv[2]);
  int nbthreads = atoi(argv[3]);

  // get string data
  char *X = new char[m];
  char *Y = new char[n];
  generateLCS(X, m, Y, n);

  int result = 0; // length of common subsequence
  std::vector<std::thread> threads (nbthreads);
  int mSubset = m / nbthreads;
  int nSubset = n / nbthreads;
  ParFor pf;

  std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
    for(int j = 0; j < nbthreads; j++) {
            threads.push_back(std::thread(&ParFor::parfor, &pf, 0, mSubset, nSubset, 1,
                 [&](int& tls) -> void{
                   tls = result;
                 },
                 [&](int a, int b, int& tls) -> void{
                          if (X[a] == Y[b])
                            tls++;
                  },
                 [&](int tls) -> void{
                   result += tls;
                 }));
        }

    for(auto& t: threads)
            t.join();

  std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;

  if(m < 10 || n < 10)
    result = 0;

  checkLCS(X, m, Y, n, result);

  std::cerr<<elapsed_seconds.count()<<std::endl;

  delete[] X;
  delete[] Y;

  return 0;
}

“类 ParFor”和从“int 结果”到最后的所有内容都是我添加的,其余的是来自 TA 的预先编写的代码。如果需要更多说明,请告诉我。谢谢。

【问题讨论】:

  • 您的代码以大量非标准标头开头。我需要继续阅读吗?请删除所有不必要的内容。
  • 另外,如果您将“模板函数”视为函数模板,它通常会变得更容易。
  • 我们不需要查看您的整个作业和整个计划。专注于您的具体问题。对于描述为 “我的问题在于将模板函数传递给我的线程” 的内容,我们需要知道的关于您的分配的所有内容就是它是一个分配(这样我们就不会偏离轨道有建议和批评)。 minimal reproducible example 将定义一个函数模板,尝试将该模板的实例传递给一个线程,而几乎没有别的。您的问题中无关紧要的噪音越少,答案就越有帮助。
  • 另外,除非我忽略了什么,否则您没有告诉我们问题出在哪里。你告诉我们你认为它在哪里,但没有确定症状。

标签: c++ multithreading templates parallel-processing header-files


【解决方案1】:

你是对的,你不能像传递函数一样传递函数模板。它们是不同的东西,就像饼干刀不是饼干一样。

您的代码中有两个主要问题。

首先,由于 ParFor::parfor 是一个模板,如果您提供的模板参数与您的 lambdas 用于 TLS 的模板参数相匹配,则只能将成员函数指针指向它,因此请将其更改为以下内容(例如):

&ParFor::parfor<int> 

您的第二个问题是试图将 lambda 传递给函数模板,并期望推断说“这个 lambda 可以转换为 std::function,所以它是匹配的,从中推断”。对于推导,它需要完全匹配类型,并且 lambda 不是 std::function。如果传入 std::function 对象,则可以推导出模板参数。

因此,更改创建线程的循环以在传递 lambda 表达式之前对其进行包装,这样它就会编译。你的代码中发生的事情太多了,我不想深入研究除此之外的细节,所以如果还有其他错误,这些仍然是你的。 :)

for(int j = 0; j < nbthreads; j++) {
    threads.push_back(std::thread(
        &ParFor::parfor<int>, &pf, 0, mSubset, nSubset, 1,
        std::function{[&](int& tls) -> void{
            tls = result;
        }},
        std::function{[&](int a, int b, int& tls) -> void {
            if (X[a] == Y[b])
                tls++;
        }},
        std::function{[&](int tls) -> void{
            result += tls;
        }}));
    }

另外,指定您的 lambda 返回 void 的尾随返回类型是多余的。您可以直接删除 -&gt; void 而无需更改任何内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-21
    • 1970-01-01
    • 2018-08-29
    • 2014-03-11
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    相关资源
    最近更新 更多