2013-03-27 9 views
38

Jedną z zalet używania zamiast ręcznego tworzenia obiektów jest to, że std::async może używać pul wątków pod okładkami, aby uniknąć problemów z nadmierną liczbą subskrypcji. Ale które implementacje to robią? Rozumiem, że implementacja Microsoftu ma, ale co z tymi innymi implementacjami async?Które implementacje std :: async używają pul wątków?

  • GNU libstdC++
  • GNU libC++ biblioteka
  • tylko oprogramowanie za
  • doładowania (dla boost::thread::async nie std::async)

Dzięki za wszelkie informacje można zaoferować.

+4

Pule wątków mogą w rzeczywistości nie być legalną implementacją ze względu na rzeczy typu 'thread_local'; na przykład 'async' jest wymagane do uruchomienia w tym samym wątku lub w nowym wątku, co oznaczałoby, że konstruktory dla zmiennych' thread_local' działają. VC++ nie implementuje jeszcze 'thread_local', ale nie jestem pewien, w jaki sposób utworzą implementację zgodną z użyciem pul wątków. – bames53

+3

@bames: 'thread_local' nie musi być naiwnym odnośnikiem do lokalnego magazynu wątków systemu operacyjnego. Środowisko wykonawcze może śledzić obiekty lokalne z wątkami i powodować ich niszczenie/resetowanie, gdy wątek "asynchroniczny" zostanie zwrócony do puli, tak jakby wątek się kończył. –

+3

@ bames53: To, czy pule wątków są legalną implementacją, jest w rzeczywistości oddzielnym pytaniem. (Sądzę, że standard został napisany z zamiarem celowym, że pule wątków są dozwolone.) Moje pytanie brzmi, które implementacje faktycznie używają pul wątków.To pytanie jest ważne, nawet jeśli kwestia ich ważności pozostaje jeszcze ustalona. – KnowItAllWannabe

Odpowiedz

39

Black Box testowania

Choć „white box” Kontrola może odbywać się poprzez inspekcję doładowania, libstdC++ lub libC++ źródeł albo sprawdzanie dokumentacji jak just::thread lub MSVC Concurrency Runtime, ale nie mogę sobie odmówić przyjemności pisania C + +11 kod!

zrobiłem 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 

Jak widać - MSVC powoduje ponowne wątki, to znaczy, że jest bardzo prawdopodobne, że jest to schemat jest jakiś rodzaj puli wątków.

+2

To jest interesujące, ale nie jestem pewien, co możemy z tego wyciągnąć. Na przykład, jeśli widzimy, że wątek ID n jest używany więcej niż jeden raz, może to oznaczać, że ten wątek był częścią puli, ale może również wskazywać, że wątek z tym identyfikatorem został uruchomiony, został zakończony, został zniszczony, a następnie identyfikator został ponownie wykorzystany przez nowy wątek. Czy błędnie odczytuję kod lub błędnie analizuję sytuację? – KnowItAllWannabe

+1

@KnowItAllWannabe, to, co mówisz, jest możliwe, i pomyślałem o takiej sytuacji. Próbuję również wyciągnąć pewne wnioski na podstawie tych wyników. Zacznijmy od zdecydowanie oczywistego: libC++, libstdC++ i Boost + {GCC, MSVC} - nie używajcie pule wątków. Tylko MSVC * możliwie * używa puli wątków. Czy sie zgadzasz? –

+0

To na pewno wygląda w ten sposób. – KnowItAllWannabe

Powiązane problemy