C ++ terminate wird ohne aktive Ausnahme aufgerufen


88

Ich erhalte einen C ++ - Fehler beim Threading:

terminate called without an active exception
Aborted

Hier ist der Code:

#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

template<typename TYPE>
class blocking_stream
{
public:
    blocking_stream(size_t max_buffer_size_)
        :   max_buffer_size(max_buffer_size_)   
    {
    }

    //PUSH data into the buffer
    blocking_stream &operator<<(TYPE &other)
    {
        std::unique_lock<std::mutex> mtx_lock(mtx); 
        while(buffer.size()>=max_buffer_size)
            stop_if_full.wait(mtx_lock);

        buffer.push(std::move(other));

        mtx_lock.unlock();
        stop_if_empty.notify_one();
        return *this;
    }
    //POP data out of the buffer 
    blocking_stream &operator>>(TYPE &other)
    {
        std::unique_lock<std::mutex> mtx_lock(mtx);
        while(buffer.empty())
            stop_if_empty.wait(mtx_lock);

        other.swap(buffer.front()); 
        buffer.pop();

        mtx_lock.unlock();
        stop_if_full.notify_one();
        return *this;
    }

private:
    size_t max_buffer_size;
    std::queue<TYPE> buffer;
    std::mutex mtx;
    std::condition_variable stop_if_empty,
                            stop_if_full;
    bool eof;   
};

Ich habe meinen Code anhand dieses Beispiels modelliert: http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

Was mache ich falsch und wie behebe ich den Fehler?


8
Haben Sie joinalle Ihre Threads in Ihrem Hauptprogramm?
Kerrek SB

Zeigen Sie uns den Rest des Codes.
Matt

2
@ Kerrek ah ha das hat das Problem behoben, ich habe keine Ahnung warum, obwohl ich sicher bin, dass der Haupt-Thread nicht beendet wurde, bevor die Arbeiter fertig waren. Sehen meine Sperralogorithmen auch richtig aus?
111111

Kompilierbarer Code, der das Problem reproduziert.
Martin York

3
Scheint, als könnte die Laufzeit in diesem Fall eine bessere Diagnose liefern?
Nemo

Antworten:


123

Wenn ein Thread-Objekt den Gültigkeitsbereich verlässt und sich im verbindbaren Zustand befindet, wird das Programm beendet. Das Standardkomitee hatte zwei weitere Optionen für den Destruktor eines verbindbaren Threads. Es könnte leise beitreten - aber beitreten könnte niemals zurückkehren, wenn der Thread stecken bleibt. Oder es könnte den Thread lösen (ein losgelöster Thread kann nicht verbunden werden). Abgelöste Threads sind jedoch sehr schwierig, da sie bis zum Ende des Programms überleben und die Freigabe von Ressourcen durcheinander bringen können. Wenn Sie Ihr Programm also nicht beenden möchten, stellen Sie sicher, dass Sie jedem Thread beitreten (oder ihn trennen).


1
"Wenn ein Thread-Objekt den Gültigkeitsbereich verlässt und sich im zusammenfügbaren Zustand befindet, wird das Programm beendet." Können Sie ein absolut einfaches, reproduzierbares Beispiel dafür liefern? Das Beispiel im OP ist etwas kompliziert.
Alec Jacobson

1
Und diese Aussage scheint dieser Antwort zu widersprechen: stackoverflow.com/a/3970921/148668
Alec Jacobson

5
@mangledorf: Beachten Sie, dass sie über Boost :: Thread sprechen und ich über std :: Thread spreche. Diese beiden haben unterschiedliche Zerstörungsverhalten. Dies war eine bewusste Entscheidung des Ausschusses.
Bartosz Milewski

Was ist, wenn Sie auf dieses Problem stoßen std::async? Wie können Sie einen dort erstellten Thread verbinden / trennen? Es scheint nicht genug zu sein, auf die resultierende Zukunft zu warten, da dies besagt, dass der Thread "möglicherweise aus einem Thread-Pool stammen könnte" und das wait () der Zukunft nicht wirklich bedeutet, einen Thread in einem Pool zu beenden (und das würde nicht) sowieso keinen Sinn für vernünftige Thread-Pools).
Jason C

1
Nur ein Update , dass in C ++ 20, std::jthreadnennt .join()in dem destructor (wie es Spielraum erlischt). Was mir persönlich besser gefällt, da es RAII besser folgt.
Pooya13

46

So reproduzieren Sie diesen Fehler:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() { 
  std::thread t1(task1, "hello"); 
  return 0;
}

Kompilieren und ausführen:

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
terminate called without an active exception
Aborted (core dumped)

Sie erhalten diesen Fehler, weil Sie Ihren Thread nicht verbunden oder getrennt haben.

Eine Möglichkeit, dies zu beheben, besteht darin, den Thread wie folgt zu verbinden:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() { 
  std::thread t1(task1, "hello"); 
  t1.join();
  return 0;
}

Dann kompilieren und ausführen:

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello

Die andere Möglichkeit, das Problem zu beheben, besteht darin, es wie folgt abzunehmen:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <thread>
using namespace std;
void task1(std::string msg){
  cout << "task1 says: " << msg;
}
int main() 
{ 
     {

        std::thread t1(task1, "hello"); 
        t1.detach();

     } //thread handle is destroyed here, as goes out of scope!

     usleep(1000000); //wait so that hello can be printed.
}

Kompilieren und ausführen:

el@defiant ~/foo4/39_threading $ g++ -o s s.cpp -pthread -std=c++11
el@defiant ~/foo4/39_threading $ ./s
task1 says: hello

Informieren Sie sich über das Trennen von C ++ - Threads und das Verbinden von C ++ - Threads.


1
In diesem Zusammenhang ist die Verwendung von usleep () nur dann sinnvoll, wenn der Thread getrennt und das Handle zerstört wurde (indem der Gültigkeitsbereich verlassen wurde). Also habe ich Ihren Code bearbeitet, um dies widerzuspiegeln.
Nawaz

17

Eric Leschinski und Bartosz Milewski haben die Antwort bereits gegeben. Hier werde ich versuchen, es anfängerfreundlicher darzustellen.

Sobald ein Thread innerhalb eines Bereichs gestartet wurde (der selbst auf einem Thread ausgeführt wird), muss explizit sichergestellt werden, dass eine der folgenden Aktionen ausgeführt wird, bevor der Thread den Bereich verlässt:

  • Die Laufzeit verlässt den Bereich erst, nachdem die Ausführung dieses Threads abgeschlossen ist. Dies wird durch Verbinden mit diesem Faden erreicht. Beachten Sie die Sprache, es ist der äußere Bereich, der sich mit diesem Thread verbindet.
  • Die Laufzeit lässt den Thread alleine laufen. Das Programm verlässt also den Bereich, unabhängig davon, ob dieser Thread ausgeführt wurde oder nicht. Dieser Thread wird von selbst ausgeführt und beendet. Dies wird durch Abnehmen des Fadens erreicht. Dies kann beispielsweise zu Problemen führen, wenn der Thread auf Variablen in diesem äußeren Bereich verweist.

Beachten Sie, dass die Ausführung des Threads zu dem Zeitpunkt, zu dem er verbunden oder getrennt wird, möglicherweise vollständig abgeschlossen ist. Dennoch muss eine der beiden Operationen explizit ausgeführt werden.


1

Jahr muss der Thread join () sein. wenn der Hauptausgang


1
Diese Antwort eignet sich wahrscheinlich eher für einen Kommentar, der an eine andere Antwort angehängt ist. Und ich muss sagen, willkommen bei Stack Overflow!
Contango

0

Solange Ihr Programm stirbt und der Thread nicht getrennt oder verbunden wird, tritt dieser Fehler auf. Ohne den Thread zu lösen und zu verbinden, sollten Sie nach dem Erstellen des Threads eine Endlosschleife geben.

int main(){

std::thread t(thread,1);

while(1){}

//t.detach();
return 0;}

Es ist auch interessant, dass sich der Faden nach dem Schlafen oder Schleifen lösen oder verbinden kann. Auch auf diese Weise erhalten Sie diesen Fehler nicht.

Das folgende Beispiel zeigt auch, dass der dritte Thread seine Arbeit nicht vor dem Hauptwürfel erledigen kann. Dieser Fehler kann aber auch nicht auftreten, solange Sie sich irgendwo im Code trennen. Der dritte Thread schläft 8 Sekunden lang, aber der Haupt-Thread stirbt in 5 Sekunden.

void thread(int n) {std::this_thread::sleep_for (std::chrono::seconds(n));}

int main() {
std::cout << "Start main\n";
std::thread t(thread,1);
std::thread t2(thread,3);
std::thread t3(thread,8);
sleep(5);

t.detach();
t2.detach();
t3.detach();
return 0;}

0

Zuerst definieren Sie einen Thread. Und wenn Sie niemals join () oder attach () aufrufen, bevor Sie den Thread-Destruktor aufrufen, wird das Programm abgebrochen.

Wenn Sie einen Thread-Destruktor aufrufen, ohne zuerst join aufzurufen (um zu warten, bis er beendet ist) oder trennen, wird garantiert, dass std :: terminate sofort aufgerufen und das Programm beendet wird.

Das implizite Trennen oder Verbinden eines joinable () - Threads in seinem Destruktor kann dazu führen, dass Fehler beim Debuggen der Korrektheit (zum Trennen) oder der Leistung (zum Verbinden) nur dann auftreten, wenn eine Ausnahme ausgelöst wird. Daher muss der Programmierer sicherstellen, dass der Destruktor niemals ausgeführt wird, solange der Thread noch verbunden werden kann.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.