【问题标题】:efficient approach in using c++ thread/ boost thread使用 c++ 线程/ boost 线程的有效方法
【发布时间】:2015-08-20 05:09:04
【问题描述】:

我有一个需要并行化的伪代码:

int thread_count=8;
for(int i=1;i<100000;i++)
{
do_work(i,record);
}

do_work 函数将基于 i 工作并将输出写入记录。现在,我想将这个序列化实现转换为多线程实现;

我知道我可以做类似的事情

int thread_count=8;
for(int i=1;i<100000;i++)
{
boost::thread t1(do_work,i,std::ref(record));
}

但这会创建数以千计的线程,从而损害性能。我相信发布的问题应该是需要多线程的最自然形式,我想知道解决这个问题的标准 c++ 实践是什么......谢谢。

【问题讨论】:

  • 您需要可移植的代码还是可以特定于给定的平台/工具集?例如,Windows 上的 VC++ 具有可以帮助完成此类任务的 PPL。

标签: c++ multithreading boost


【解决方案1】:

创建多个线程有助于提高性能,因为每个线程都可以在自己的核心中运行,而不会影响另一个。但是你说他们do_work() 函数写入记录。如果在这种情况下使用mutex 在线程之间共享该变量,即使您在它们自己的内核上运行线程,也会严重降低性能。

在这种情况下,自旋锁可以帮助减少互斥锁的时间开销,但它仍然基于std::atomic_flag(至少boost::spinlock 是在 GNU g++ 上编译时),它是一个原子变量,因此需要同步缓存的开销。您应该只将其并行化到每个线程可以在独立内核中运行的程度。

除非你的程序就像一个服务器,你需要在不阻塞其他请求的情况下处理请求。在这种情况下,线程池(可能动态增长和收缩)应该是正确的选择。像 Apache 这样的服务器在很多情况下也使用线程池

【讨论】:

  • 感谢您的回答,我认为使用互斥锁及其延迟对我来说不是一个大问题......现在对我来说的困难是,即使我需要运行 do_work() 100000 次,我也会最多只能创建 8 个线程,一旦完成一些线程,我就可以创建一个新线程并做一些事情......但是这样做的标准做法是什么?我应该制作自己的自定义代码吗?我相信这应该是多线程中最常见的问题...谢谢。
  • 您可以运行 8 个线程。并通过线程安全队列将任务传递给线程。所以每个线程都会等待,直到它通过队列接收到一个任务。或者您需要向主线程发出信号,表明您的一个正在运行的线程已经完成,因此可以通过信号量或future(查看std::async)之类的东西创建另一个线程。然而,创建新线程的开销可能会贵一些。就性能而言,线程安全队列的实现也很重要
【解决方案2】:

一个好的方法是使用并行算法,例如TBB parallel_for_each。在后台,它将为您创建一个(全局)线程池,并在所有可用 CPU 上安排工作块/任务,而不会超额订阅,例如它不会创建比可用 CPU 更多的工作线程。

【讨论】:

    【解决方案3】:

    您可以使用 OpenMP 吗?只需在循环前添加#pragma omp parallel for 并为编译器启用openmp 支持

    【讨论】:

    • 它会处理所有的数据竞争吗??
    【解决方案4】:

    这是线程池的完美候选者。如果您不需要等待结果,简单的线程池就足够了。如果您需要等待结果并根据结果执行其他操作,则需要基于未来的池。我为我的工作用 C++ 编写了它的两个版本,如果你愿意,我很乐意分享。线程池是优化使用多核处理器资源的好方法。

    【讨论】:

      猜你喜欢
      • 2011-02-09
      • 2013-02-03
      • 1970-01-01
      • 2011-09-13
      • 1970-01-01
      • 1970-01-01
      • 2011-07-06
      • 1970-01-01
      • 2012-03-17
      相关资源
      最近更新 更多