【问题标题】:Boost Threading Conceptualization / Questions提升线程概念化/问题
【发布时间】:2013-01-20 06:40:14
【问题描述】:

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

首先,浏览所有 boost 文档和示例真的让我很困惑,我不确定我在寻找什么。提升::线程?推动未来?有人可以举例说明适用于我的情况。此外,我不明白如何指定要运行多少个线程,是否更像是我会运行 50 个线程并且操作系统处理何时执行它们?

【问题讨论】:

  • 对于std::asyncstd::future(或它们的 Boost 变体)来说,这似乎是一项不错的工作。

标签: c++ multithreading boost boost-thread


【解决方案1】:

如果您的代码完全受 CPU 限制(无网络/磁盘 IO),那么您将受益于启动与 CPU 一样多的后台线程。使用 Boost 的 hardware_concurrency() 函数来确定该数字和/或允许用户设置它。仅仅启动一堆线程是没有用的,因为这会增加创建、切换和终止线程所带来的开销。

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

【讨论】:

    【解决方案2】:

    阅读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,这将创建三个新线程然后在main()线程中同步调用run_sim,然后再创建另外三个新线程然后同步调用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();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-25
      • 2013-09-07
      • 1970-01-01
      • 2010-11-19
      • 2011-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多