2012-05-14 12 views
7

Używam C++ 11 na Mac OS Xcode 4.3.2 std :: async używa tego samego wątku i mój kod nie osiąga równoległości. W poniższym przykładowym kodzie chcę utworzyć 10 nowych wątków. W każdym wątku chcę obliczyć pierwiastek kwadratowy zmiennej wejściowej i ustawić wynik w obietnicy. w głównej funkcji chcę wyświetlić wyniki wyliczone z wątków. Wywołuję std :: async z uruchomieniem zasad :: async, więc oczekuję, że utworzy nowy wątek (10 razy).std :: async używa tego samego wątku, a mój kod nie zapewnia równoległości.

#include <mutex> 
    #include <future> 
    #include <thread> 
    #include <vector> 
    #include <cmath> 
    #include <iostream> 

    using namespace std; 
    mutex iomutex; 

    void foo(int i, promise<double> &&prms) 
    { 
     this_thread::sleep_for(chrono::seconds(2)); 
     prms.set_value(sqrt(i)); 
     { 
      lock_guard<mutex> lg(iomutex); 
      cout << endl << "thread index=> " << i << ", id=> "<< this_thread::get_id(); 
     } 
    } 

    int main() 
    { 
     { 
      lock_guard<mutex> lg(iomutex); 
      cout << endl << "main thread id=>"<< this_thread::get_id(); 
     } 
     vector<future<double>> futureVec; 
     vector<promise<double>> prmsVec; 

     for (int i = 0; i < 10; ++i) { 
      promise<double> prms; 
      future<double> ftr = prms.get_future(); 
      futureVec.push_back(move(ftr)); 
      prmsVec.push_back(move(prms)); 

      async(launch::async, foo, i, move(prmsVec[i])); 
     } 

     for (auto iter = futureVec.begin(); iter != futureVec.end(); ++iter) { 
      cout << endl << iter->get(); 
     } 

     cout << endl << "done"; 

     return 0; 

    } 

Jednak jeśli używam std :: thread, to mogę osiągnąć równoległość.

#include <mutex> 
    #include <future> 
    #include <thread> 
    #include <vector> 
    #include <cmath> 
    #include <iostream> 

    using namespace std; 
    mutex iomutex; 

    void foo(int i, promise<double> &&prms) 
    { 
     this_thread::sleep_for(chrono::seconds(2)); 
     prms.set_value(sqrt(i)); 
     { 
      lock_guard<mutex> lg(iomutex); 
      cout << endl << "thread index=> " << i << ", id=> "<< this_thread::get_id(); 
     } 
    } 

    int main() 
    { 
     { 
      lock_guard<mutex> lg(iomutex); 
      cout << endl << "main thread id=>"<< this_thread::get_id(); 
     } 
     vector<future<double>> futureVec; 
     vector<promise<double>> prmsVec; 
     vector<thread> thrdVec; 
     for (int i = 0; i < 10; ++i) { 
      promise<double> prms; 
      future<double> ftr = prms.get_future(); 
      futureVec.push_back(move(ftr)); 
      prmsVec.push_back(move(prms)); 

      thread th(foo, i, move(prmsVec[i])); 
      thrdVec.push_back(move(th)); 
     } 

     for (auto iter = futureVec.begin(); iter != futureVec.end(); ++iter) { 
      cout << endl << iter->get(); 
     } 
     for (int i = 0; i < 10; ++i) { 
      thrdVec[i].join(); 
     } 
     cout << endl << "done"; 

     return 0; 

    } 
+0

realizacja 'thread' biblioteki na starszych gccs naprawdę nie jest funkcjonalne. Spróbuj na coś nie-starożytnego. – pmr

+0

@pmr: Myślałem, że Clang był domyślnym kompilatorem w Xcode 4.2+? – ildjarn

+0

@ildjarn Masz rację, oczywiście. Pomyliłem się, że 4.3.2 oznacza wersję gcc (XCode używał gcc 4. coś przez długi czas). – pmr

Odpowiedz

16
  async(launch::async, foo, i, move(prmsVec[i])); 

Linia ta zwraca future ale ponieważ nie przypisać go do niczego destructor przyszłości rozpoczyna się na końcu zestawienia, który blokuje i czeka na wynik poprzez wywołanie std::future::wait()

Dlaczego czy w każdym razie ręcznie dzwonisz pod numer std::async, jeśli mimo to wróci on do przyszłości? Celem async jest to, że nie musisz ręcznie używać obietnicy, która jest wykonywana wewnętrznie dla ciebie.

przepisać foo() wrócić double następnie wywołać ją z async

#include <mutex> 
#include <future> 
#include <thread> 
#include <vector> 
#include <cmath> 
#include <iostream> 

using namespace std; 
mutex iomutex; 

double foo(int i) 
{ 
    this_thread::sleep_for(chrono::seconds(2)); 
    lock_guard<mutex> lg(iomutex); 
    cout << "\nthread index=> " << i << ", id=> "<< this_thread::get_id(); 
    return sqrt(i); 
} 

int main() 
{ 
    cout << "\nmain thread id=>" << this_thread::get_id(); 
    vector<future<double>> futureVec; 

    for (int i = 0; i < 10; ++i) 
     futureVec.push_back(async(launch::async, foo, i)); 

    for (auto& fut : futureVec) 
    { 
     auto x = fut.get(); 
     lock_guard<mutex> lg(iomutex); 
     cout << endl << x; 
    } 

    cout << "\ndone\n"; 
} 
+0

Gdy jesteśmy w pętli for, jest to kod sekwencyjny. Nie ma potrzeby muteksa tutaj. – Jagannath

+0

Chciałem wykorzystać obietnicę i asynchronię razem. Czy to oznacza, że ​​jeśli użyjemy Promise z std :: async, to nie będzie on zachowywał się jak asynchronicznie i zawsze będzie zachowywał się jak połączenie sync? –

+0

@Jagannath: nie, w pierwszej iteracji, którą czekałeś na jedną przyszłość, istnieje dziewięć wątków, które wciąż mogą być uruchomione i zapisywane do cout. W drugiej iteracji może być jeszcze osiem wątków piszących do cout itd. (@ Dzięki za ulepszenia kodu) –

Powiązane problemy