2014-01-24 8 views
7

Manchmal wäre es nützlich, wenn ein verknüpfbarer std::thread die Fähigkeit hätte, thread::join() auf seinem Destruktor auszuführen. Siehe die folgenden Beispiele.Was ist der Grund für ein Joinable std :: Thread nicht automatisch beitreten?

Beispiel 1 (Fehler): Das Objekt std::thread hat nach dem Wurf von der Ausnahme, zerstört. Sobald der Ablauf den Gültigkeitsbereich verlässt, wird der Destruktor aufgerufen, BEVOR der Join stattfindet. Es zeigt STL die Fehlermeldung 'abort' an.

int main(int argc, const char * argv[]) 
{ 
    try 
    { 
     thread t([]() 
     { 
      this_thread::sleep_for(chrono::seconds(1)); 
      cout << "thread done" << endl; 
     }); 

     throw exception("some exception"); 

     t.join(); 
    } 
    catch (const exception &) 
    { 
     cout << "exception caught!" << endl; 
    } 

    cout << "main done" << endl; 

    return 0; 
} 

Beispiel 2 (richtiger Weg): Das Objekt t vor meinem try-catch-Block erstellt wird und die join() auf beide versuchen und Catch-Blöcke gesetzt wird. So garantiert es, dass die Join() passiert.

int main(int argc, const char * argv[]) 
{ 
    thread t; 

    try 
    { 
     t = thread([]() 
     { 
      this_thread::sleep_for(chrono::seconds(1)); 
      cout << "thread done" << endl; 
     }); 

     throw exception("some exception"); 

     t.join(); 
    } 
    catch (const exception &) 
    { 
     t.join(); 
     cout << "exception caught!" << endl; 
    } 

    cout << "main done" << endl; 

    return 0; 
} 

... und die Frage ist: Was ist der Grund für ein joinable std::thread ist nicht automatisch auf seinem destructor anschließen?

Es wäre viel einfacher, wenn es automatisch passiert. Die Art und Weise, wie es heute gemacht wird erfordert, dass man vorsichtig sein muss, wenn man beispielsweise Threads innerhalb von Try-Catch-Blöcken verwendet ... aber ich bin mir sicher, dass jemand bei der Entwicklung dachte, std::thread auf diese Weise. Also muss es einen Grund dafür geben ... aus welchem ​​Grund?

PS: Ich weiß, wir std::thread in einer Klasse envolve können und setzen Sie den join() auf der destructor dieser neuen Klasse ... so wird es automatisch. Aber das ist nicht der Punkt. Meine Frage ist wirklich über std::thread selbst.

+0

Trennung von Bedenken. Wenn du ein Ding haben willst, das einen Faden startet und auf seine Vollendung auf Zerstörung wartet, schreibe es. –

+1

Beachten Sie, dass der obige Code nicht garantiert, dass 'join()' passiert. In C++ können Sie einen Wert eines beliebigen Typs übergeben - er muss nicht von "std :: exception" abgeleitet werden. Wenn Sie in C++ sicherstellen müssen, dass eine Aktion ausgeführt wird (ob eine Ausnahme ausgelöst wird oder nicht), verwenden Sie ein RAII-Handle, bei dem die Bereinigung im Destruktor erfolgt. – zmb

+0

darüber, ok, nahm ich nur das Werfen von std :: Ausnahme. aber ich verstehe was du meinst. –

Antwort

14

Der Grund ist einfach, so dass Sie gezwungen sind, darüber nachzudenken. Wenn ein std::thread-Objekt aufgrund einer Ausnahme, die den Gültigkeitsbereich verlässt, zerstört wird, kann ein Join eine blockierende Wartezeit während des Abwickelns des Stacks verursachen, was oft unerwünscht ist und zum Deadlock führen kann, wenn der wartende Thread wiederum auf eine Aktion wartet seitens des Threads, der das Warten erledigt.

Wenn die Anwendung in dieser Situation beendet wird, müssen Sie als Programmierer aktiv über die Bedingungen nachdenken, die zur Zerstörung des Objekts führen, und sicherstellen, dass der Thread korrekt verbunden ist.

+1

Ja - klingt wie ein perfektes Rezept für Shutdown-Fehler. –