2013-03-27 40 views
38

使用std::async而不是手动创建std::thread对象的优点之一应该是std::async可以在封面下使用线程池来避免超额订阅问题。但是,哪些实现可以这样做我的理解是微软的实施,但这些其他async实现呢?哪个std :: async实现使用线程池?

  • GNU的的libstdC++
  • GNU的libc中++
  • 不仅仅是软件的图书馆
  • 升压(为boost::thread::async,不std::async

感谢您能提供的任何信息。

+4

线程池可能实际上并不是一个合法的实现,因为'thread_local';例如'async'需要在同一个线程上运行,或者像在一个新线程上运行,这意味着'thread_local'变量的构造函数会运行。 VC++没有实现'thread_local',但我不知道他们将如何使用线程池创建一致的实现。 – bames53 2013-03-27 18:30:36

+3

@bames:'thread_local'不必是对操作系统线程本地存储的简单引用。运行时可以跟踪线程本地对象,并在“异步”工作线程返回到池时导致它们被销毁/重置,就像线程正在结束一样。 – 2013-03-27 19:06:35

+3

@ bames53:线程池是否是合法实现实际上是一个单独的问题。 (我相信这个标准的写意是允许线程池被允许的。)我的问题是哪些实现实际上使用了线程池。即使问题的有效性尚待确定,这个问题仍然存在。 – KnowItAllWannabe 2013-03-27 19:22:02

回答

39

黑盒测试

虽然“白盒”检查可以通过检查推动,的libstdC++或的libC++源代码,或检查像just::threadMSVC Concurrency Runtime文档做,但我不能否认自己编写C +的乐趣+11码!

我已black-box test

LIVE DEMO

#define BOOST_THREAD_PROVIDES_FUTURE 
#define BOOST_RESULT_OF_USE_DECLTYPE 
#include <boost/exception/exception.hpp> 
#include <boost/range/algorithm.hpp> 
#include <boost/move/iterator.hpp> 
#include <boost/phoenix.hpp> 
#include <boost/thread.hpp> 
#include <boost/config.hpp> 

#include <unordered_set> 
#include <functional> 
#include <algorithm> 
#include <iterator> 
#include <iostream> 
#include <ostream> 
#include <cstddef> 
#include <string> 
#include <vector> 
#include <future> 
#include <thread> 
#include <chrono> 
#include <mutex> 

// _____________________[CONFIGURATION]________________________ // 
namespace async_lib = std; 
const bool work_is_sleep = false; 
// ____________________________________________________________ // 

using namespace std; 
using boost::phoenix::arg_names::arg1; 
using boost::thread_specific_ptr; 
using boost::back_move_inserter; 
using boost::type_name; 
using boost::count_if; 
using boost::copy; 

template<typename Mutex> 
unique_lock<Mutex> locker(Mutex &m) 
{ 
    return unique_lock<Mutex>(m); 
} 

void do_work() 
{ 
    if(work_is_sleep) 
    { 
     this_thread::sleep_for(chrono::milliseconds(20)); 
    } 
    else 
    { 
     volatile double result=0.0; 
     for(size_t i=0; i!=1<<22; ++i) 
      result+=0.1; 
    } 
} 

int main() 
{ 
    typedef thread::id TID; 
    typedef async_lib::future<TID> FTID; 

    unordered_set<TID> tids, live_tids; 
    vector<FTID> ftids; 
    vector<int> live_tids_count; 
    async_lib::mutex m; 
    generate_n 
    (
     back_move_inserter(ftids), 64*thread::hardware_concurrency(), 
     [&]() 
     { 
      return async_lib::async([&]() -> TID 
      { 
       static thread_specific_ptr<bool> fresh; 
       if(fresh.get() == nullptr) 
        fresh.reset(new bool(true)); 
       TID tid = this_thread::get_id(); 
       locker(m), 
        live_tids.insert(tid), 
        live_tids_count.push_back(int(live_tids.size()) * (*fresh ? -1 : 1)); 
       do_work(); 
       locker(m), 
        live_tids.erase(tid); 
       *fresh = false; 
       return tid; 
      }); 
     } 
    ); 
    transform 
    (
     begin(ftids), end(ftids), 
     inserter(tids, tids.end()), 
     [](FTID &x){return x.get();} 
    ); 

    cout << "Compiler = " << BOOST_COMPILER        << endl; 
    cout << "Standard library = " << BOOST_STDLIB      << endl; 
    cout << "Boost = " << BOOST_LIB_VERSION        << endl; 
    cout << "future type = " << type_name<FTID>()      << endl; 
    cout << "Only sleep in do_work = " << boolalpha << work_is_sleep << endl; 
    cout << string(32,'_')            << endl; 
    cout << "hardware_concurrency = " << thread::hardware_concurrency() << endl; 
    cout << "async count = " << ftids.size()       << endl; 
    cout << "unique thread id's = " << tids.size()      << endl; 
    cout << "live threads count (negative means fresh thread):"    ; 
    copy(live_tids_count, ostream_iterator<int>(cout," "));  cout << endl; 
    cout << "fresh count = " << count_if(live_tids_count, arg1 < 0)  << endl; 
} 

Compiler = Microsoft Visual C++ version 11.0 
Standard library = Dinkumware standard library version 540 
Boost = 1_53 
future type = class std::future<class std::thread::id> 
Only sleep in do_work = false 
________________________________ 
hardware_concurrency = 4 
async count = 256 
unique thread id's = 4 
live threads count (negative means fresh thread):-1 -2 2 2 -3 -4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 
fresh count = 4 

Compiler = Microsoft Visual C++ version 11.0 
Standard library = Dinkumware standard library version 540 
Boost = 1_53 
future type = class std::future<class std::thread::id> 
Only sleep in do_work = true 
________________________________ 
hardware_concurrency = 4 
async count = 256 
unique thread id's = 34 
live threads count (negative means fresh thread):-1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 18 18 18 18 18 18 18 18 18 18 18 18 18 
18 18 18 18 -19 19 -20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 -21 21 21 -22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 - 
23 23 23 23 -24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 24 -25 25 25 25 25 -26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 
26 26 26 -27 27 27 27 27 27 -28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 -29 29 29 29 29 29 29 -30 30 30 30 30 30 30 30 30 30 
30 30 30 30 30 30 30 30 30 30 30 30 30 30 -31 31 31 31 31 31 31 31 -32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 -33 33 
33 33 33 33 33 33 33 -34 34 34 34 34 34 34 34 34 11 12 11 12 13 14 15 16 15 10 11 12 13 14 
fresh count = 34 

Compiler = Microsoft Visual C++ version 11.0 
Standard library = Dinkumware standard library version 540 
Boost = 1_53 
future type = class boost::future<class std::thread::id> 
Only sleep in do_work = false 
________________________________ 
hardware_concurrency = 4 
async count = 256 
unique thread id's = 256 
live threads count (negative means fresh thread):-1 -2 -2 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -3 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -3 -4 -4 -4 -4 -4 -4 -4 
-4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -2 -3 -3 -3 -3 -4 -4 -4 -4 -2 -2 -2 -2 -3 
-2 -2 -3 -1 -2 -2 -3 -3 -1 -2 -1 -2 -3 -2 -2 -2 -2 -1 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -3 -3 -2 -2 -2 -2 -3 -3 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 
-2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -3 -1 -2 -1 -2 -1 -2 -1 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -3 -3 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 
-2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -3 -3 -2 -2 -3 -1 -2 -1 -2 -2 -2 -3 -2 -3 -1 -2 -2 -2 -3 -2 -3 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 
-2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -3 -3 -3 -2 -2 -2 -3 
fresh count = 256 

Compiler = Microsoft Visual C++ version 11.0 
Standard library = Dinkumware standard library version 540 
Boost = 1_53 
future type = class boost::future<class std::thread::id> 
Only sleep in do_work = true 
________________________________ 
hardware_concurrency = 4 
async count = 256 
unique thread id's = 256 
live threads count (negative means fresh thread):-1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -2 
8 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 
-66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 
-103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 
-133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 
-163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 
-193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 
-223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252 
-253 -254 -255 -256 
fresh count = 256 

Compiler = GNU C++ version 4.8.0-alpha20121216 20121216 (experimental) 
Standard library = GNU libstdc++ version 20121216 
Boost = 1_53 
future type = std::future<std::thread::id> 
Only sleep in do_work = false 
________________________________ 
hardware_concurrency = 4 
async count = 256 
unique thread id's = 1 
live threads count (negative means fresh thread):-1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
fresh count = 1 

Compiler = GNU C++ version 4.8.0-alpha20121216 20121216 (experimental) 
Standard library = GNU libstdc++ version 20121216 
Boost = 1_53 
future type = boost::future<std::thread::id> 
Only sleep in do_work = false 
________________________________ 
hardware_concurrency = 4 
async count = 256 
unique thread id's = 122 
live threads count (negative means fresh thread):-1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -20 -21 -22 -23 -24 -25 -25 -26 -27 -28 -29 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -59 -60 -61 -62 -63 -64 -64 -64 -63 -61 -55 -48 -41 -33 -34 -27 -27 -28 -29 -29 -30 -31 -31 -30 -28 -29 -28 -28 -28 -29 -30 -30 -31 -30 -31 -31 -31 -32 -31 -26 -24 -25 -26 -25 -23 -23 -22 -20 -21 -19 -20 -20 -19 -20 -21 -21 -22 -21 -22 -23 -24 -24 -25 -26 -27 -25 -25 -25 -22 -23 -22 -23 -23 -24 -25 -26 -27 -27 -28 -29 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -51 -52 -53 -54 -55 -56 -57 -56 -54 -3 -3 -4 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -55 -56 -57 -58 -59 -60 -61 -61 -61 -62 -63 -64 -65 -64 -62 -63 -63 -61 -62 -61 -59 -60 -59 -57 -55 -56 
fresh count = 256 

Compiler = Clang version 3.2 (tags/RELEASE_32/final) 
Standard library = libc++ version 1101 
Boost = 1_53 
future type = NSt3__16futureINS_11__thread_idEEE 
Only sleep in do_work = false 
________________________________ 
hardware_concurrency = 4 
async count = 256 
unique thread id's = 255 
live threads count (negative means fresh thread):-1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -121 -122 -122 -123 -123 -124 -125 -126 -127 -126 -127 -128 -129 -129 -128 -129 -128 -129 -129 -128 -129 -129 -128 -126 -127 -128 -128 -129 -129 -130 -129 -129 -128 -129 -129 -130 -131 -132 -133 -134 -135 -136 -134 -132 -133 -134 -134 -133 -132 -133 -132 -133 -134 -133 -131 -129 -127 -124 -125 -121 -119 -120 -118 -119 -118 -117 -115 -111 -107 -105 -106 -103 -100 -97 -95 -96 -94 -90 -87 -81 -73 -74 -71 -72 -73 -74 -75 -70 -71 -66 -60 -59 -60 -61 -62 -63 -64 -61 -58 -55 -55 -52 -53 -54 -54 -55 -56 -56 -57 -54 -55 -56 -56 -57 -57 -58 -56 -54 -55 -56 -56 -57 -58 -58 -59 -58 -58 -58 -58 -59 -60 
fresh count = 256 

可以看出 - MSVC不重用线程,也就是说,它很可能是它的方案某种线程池。

+2

这很有趣,但我不确定我们可以从中得出什么结论。例如,如果我们看到线程ID n被多次使用,那可能表示该线程是池的一部分,但它也可能表示具有该ID的线程已启动,运行完成,被销毁,然后该ID由一个新线程重新使用。还是我误解了代码或错误分析了这种情况? – KnowItAllWannabe 2013-04-03 04:17:46

+1

@KnowItAllWannabe,你在说什么是可能的,我想过这种情况。我也试图根据这些结果做出一些结论。让我们从显而易见的开始:libC++,libstdC++和Boost + {GCC,MSVC} - 不使用线程池。只有MSVC *可能*使用线程池。你同意吗? – 2013-04-03 10:54:18

+0

它看起来确实如此。 – KnowItAllWannabe 2013-04-03 17:11:43