2013-01-20 112 views
2

我有一個通常運行50次的函數(運行50次模擬)。通常這是按順序單線程完成的,但我想用多線程來加快速度。線程不需要訪問每個其他的內存或數據,所以我不認爲賽車是一個問題。本質上,線程應該完成它的任務,並返回到主完成它,也返回一個double值。提升線程概念化/問題

首先,仔細查看所有boost文檔和示例,讓我非常困惑,而且我不知道我在找什麼。 boost :: thread?推動未來?有人能舉出一個適用於我的案例的例子嗎?此外,我不明白如何指定要運行多少個線程,更像是運行50個線程,操作系統處理何時執行它們?

+1

這似乎是['標準:: async'一個很好的工作, ](http://en.cppreference.com/w/cpp/thread/async)和['std :: future'](http://en.cppreference.com/w/cpp/thread/future)(或他們的Boost變體)。 –

回答

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個線程,因爲主線程停止執行一些工作,這將允許一些其他線程完成。

上面的代碼需要加速的相當最新版本,它是稍微容易使用標準C++,如果你可以使用C++ 11:

#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(); 
} 
4

如果您的代碼完全受CPU限制(無網絡/磁盤IO),那麼您將受益於像CPU一樣啓動儘可能多的後臺線程。使用Boost的hardware_concurrency()函數來確定該數字和/或允許用戶設置它。剛開始一堆線程沒有用,因爲這會增加創建,切換和終止線程所帶來的開銷。

啓動線程的代碼是一個簡單的循環,然後是另一個循環等待線程完成。你也可以使用thread_group類。如果作業數量未知並且無法在線程啓動時分發,請考慮使用線程池,在該線程池中,您只需啓動合理數量的線程,然後在出現時爲其提供作業。