扩展线程运行时的c ++并发问题

Posted

技术标签:

【中文标题】扩展线程运行时的c ++并发问题【英文标题】:c++ concurrency issue with scaling thread runtime 【发布时间】:2016-12-10 23:02:34 【问题描述】:

我有一个在大型数组上执行相同功能的程序。我将数组分成相等的块并将它们传递给线程。当前线程执行函数并返回它们应该执行的操作,但是我添加的线程越多,每个线程运行所需的时间就越长。这完全否定了并发的目的。我试过std::threadstd::async 都得到相同的结果。在下面的图像中,所有子线程和主线程处理的数据量相同(主线程还有 6 个点),但是主线程在大约 12 秒内运行的数据量大约是线程数的 12 倍,就好像他们异步运行。但是它们都是同时开始的,如果我从每个线程输出它们是同时运行的。这与他们的加入方式有关吗?我已经尝试了我能想到的一切,非常感谢任何帮助/建议!在示例代码中,main 直到子线程完成后才运行该函数,如果我在 main 运行后放置 join,它仍然不会运行,直到子线程完成。下面您可以看到使用 3 和 5 个线程运行时的运行时。这些时间是在一个缩小的数据集上进行测试的。

void foo(char* arg1, long arg2, std::promise<std::vector<std::vector<std::vector<std::vector<std::vector<long>>>>>> & ftrV) 
  std::vector<std::vector<std::vector<std::vector<std::vector<long>>>>> Grid;

  // does stuff....
  // fills in "Grid"

  ftrV.set_value(Grid);



int main()

  int thnmb = 3;    // # of threads
  std::vector<long> buffers;    // fill in buffers
  std::vector<char*> pointers;  //fill in pointers 

  std::vector<std::promise<std::vector<std::vector<std::vector<std::vector<std::vector<long>>>>>>> PV(thnmb); // vector of promise grids
  std::vector<std::future<std::vector<std::vector<std::vector<std::vector<std::vector<long>>>>>>> FV(thnmb);    // vector of futures grids
  std::vector<std::thread> th(thnmb);   // vector of threads
  std::vector<std::vector<std::vector<std::vector<std::vector<std::vector<long>>>>>> vt1(thnmb);    // vector to store thread grids

  for (int i = 0; i < thnmb; i++) 

    th[i] = std::thread(&foo, pointers[i], buffers[i], std::ref(PV[i]));
  
  for (int i = 0; i < thnmb; i++) 
    FV[i] = PV[i].get_future();
  

  for (int i = 0; i < thnmb; i++) 
    vt1[i] = FV[i].get();
  

  for (int i = 0; i < thnmb; i++) 
    th[i].join();
  

  // main performs same function as foo here

  // combine data
  // do other stuff..

  return(0);

【问题讨论】:

您应该将命令窗口的内容复制并粘贴到问题中,而不是发布屏幕截图。 注意到@1201ProgramAlarm 【参考方案1】:

如果不知道foo 做了什么,很难给出明确的答案,但您可能会遇到内存访问问题。每次访问您的 5 维数组都需要 5 次内存查找,并且只需要 2 或 3 个线程访问内存即可达到典型系统所能提供的饱和度。

main 应该在创建线程之后但在获得承诺值之前执行它的foo 工作。

并且foo 应该以ftrV.set_value(std::move(Grid)) 结尾,这样就不必制作该数组的副本。

【讨论】:

谢谢!我相信您对内存访问问题是正确的。昨晚做了更多阅读后,我认为这可能与错误共享有关,但是每个线程正在访问的向量块的间隔比我的机器缓存线长 1000 倍,所以我不确定这是问题。我使用 5 维数组,因为以这种方式考虑我的数据集更直观(我知道它可能看起来不是这样),我可以通过一些更改将其分解为 2D 向量,这会减少内存查找成本? 如果您可以将其更改为更平坦的 2D 向量> 类型应该会有所帮助,因为它只需要进行 2 次内存查找即可访问 2 个向量而不是 5 个。

以上是关于扩展线程运行时的c ++并发问题的主要内容,如果未能解决你的问题,请参考以下文章

深入浅出协程线程和并发问题

深入浅出协程线程和并发问题

c# 多线程的问题

有没有办法使用类的成员函数在并发线程中运行而无需在 C++11 中传递 *this?

多线程上下文切换

多线程上下文切换优化与注意