提升线程概念化/问题

时间:2013-01-20 06:40:14

标签: c++ multithreading boost boost-thread

我有一个通常运行50次的功能(运行50次模拟)。通常这是按顺序单线程完成的,但我希望使用多个线程加快速度。线程不需要访问彼此的内存或数据,所以我不认为赛车是一个问题。本质上,线程应该只完成它的任务,然后返回到它已经完成的主程序,也返回一个双精度值。

首先,查看所有提升文档和示例确实令我感到困惑,我不确定我还在寻找什么。 boost :: thread?推动未来?有人可以举例说明我的案例中适用的内容。另外,我不明白如何指定要运行的线程数,是否更像是运行50个线程并且OS处理何时执行它们?

2 个答案:

答案 0 :(得分:4)

如果您的代码完全受CPU限制(没有网络/磁盘IO),那么您可以从启动尽可能多的后台线程中获益。使用Boost的hardware_concurrency()函数来确定该数字和/或允许用户进行设置。只是启动一堆线程没有用,因为这会增加创建,切换和终止线程所带来的开销。

启动线程的代码是一个简单的循环,然后是另一个循环来等待线程的完成。您也可以使用thread_group类。如果作业数量未知并且无法在线程启动时分发,请考虑使用线程池,您只需启动合理数量的线程,然后在它们出现时为其提供作业。

答案 1 :(得分:1)

阅读Boost.Thread Futures文档,了解使用期货和async来实现这一目标。它还展示了如何使用thread对象手动(艰难的方式)。

鉴于此序列号:

double run_sim(Data*);

int main()
{
  const unsigned ntasks = 50;

  double results[ntasks];
  Data data[ntasks];

  for (unsigned i=0; i<ntasks; ++i)
    results[i] = run_sim(data[i]);
}

天真的并行版本将是:

#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/thread/future.hpp>
#include <boost/bind.hpp>

double run_task(Data*);

int main()
{
  const unsigned nsim = 50;

  Data data[nsim];
  boost::future<int> futures[nsim];

  for (unsigned i=0; i<nsim; ++i)
    futures[i] = boost::async(boost::bind(&run_sim, &data[i]));

  double results[nsim];
  for (unsigned i=0; i<nsim; ++i)
    results[i] = futures[i].get();
}

因为boost::async还不支持延迟函数,所以每个异步调用都会创建一个新线程,因此这将一次产生50个线程。这可能会非常糟糕,因此您可以将其拆分为更小的块:

#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/thread/future.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>

double run_sim(Data*);

int main()
{
  const unsigned nsim = 50;
  unsigned nprocs = boost::thread::hardware_concurrency();
  if (nprocs == 0)
    nprocs = 2;   // cannot determine number of cores, let's say 2

  Data data[nsim];   
  boost::future<int> futures[nsim];
  double results[nsim];

  for (unsigned i=0; i<nsim; ++i)
  {
    if ( ((i+1) % nprocs) != 0 )
      futures[i] = boost::async(boost::bind(&run_sim, &data[i]));
    else
      results[i] = run_sim(&data[i]);
  }

  for (unsigned i=0; i<nsim; ++i)
    if ( ((i+1) % nprocs) != 0 )
      results[i] = futures[i].get();
}

如果hardware_concurrency()返回4,这将创建三个新线程,然后在run_sim线程中同步调用main(),然后创建另外三个新线程,然后同步调用run_sim。这将阻止所有50个线程同时被创建,因为主线程停止执行某些工作,这将允许其他一些线程完成。

上面的代码需要相当新版本的Boost,如果可以使用C ++ 11,使用标准C ++会稍微容易一些:

#include <future>

double run_sim(Data*);

int main()
{
  const unsigned nsim = 50;
  Data data[nsim];

  std::future<int> futures[nsim];
  double results[nsim];

  unsigned nprocs = std::thread::hardware_concurrency();
  if (nprocs == 0)
    nprocs = 2;

  for (unsigned i=0; i<nsim; ++i)
  {
    if ( ((i+1) % nprocs) != 0 )
      futures[i] = std::async(boost::launch::async, &run_sim, &data[i]);
    else
      results[i] = run_sim(&data[i]);
  }

  for (unsigned i=0; i<nsim; ++i)
    if ( ((i+1) % nprocs) != 0 )
      results[i] = futures[i].get();
}