Application.exe has triggered a breakpoint Visual Studio 2015 C++



  • @Schlangenmensch

    if (!isRunning()) // kann es passieren, dass du Execute aufrust und der Thread schon läuft? Du startest den doch hier erst und willst dann auf die Beendigung warten
    

    eigentlich nicht, da ich bei jeden Zugriff (refernce von Obj) auf das Objekt "VisaAgilent" immer darauf achte dass der Thread beendet wird.
    Diese ist zu sehen in:

    VisaAgilent::t_enRspType VisaAgilent::Execute(const char *strCmd_p, const int iWaitResponse_p, const int iTimeout_p, const int iRspDelayed_p)
    {
    	CAgilentLan::t_enRspType enRetVal_l = enRspOffline;
    
    	if (!isRunning())
    	{
    		m_ByteArrayRead.clear();
    
    		m_ByteArrayWrite.clear();
    		m_ByteArrayWrite.append(strCmd_p);
    
    		m_iWaitResponse = iWaitResponse_p;
    		m_iTimeout = iTimeout_p;
    		m_iResponseDelayed = iRspDelayed_p;
    
    		start();
    
    		m_MtxProcess.lock();
    		m_WaitCondProcess.wait(&m_MtxProcess,-1);
    		m_MtxProcess.unlock();// Prozess wird immer freigegeben
    
    		enRetVal_l = this->m_enRetVal;
    	}
    	else
    	{
    		enRetVal_l = enRspError;
    	}
    
    	while(isRunning());
    
    	return enRetVal_l;
    }
    

    Also

    VisaAgilent::t_enRspType VisaAgilent::Execute(.....)
    

    ist eine zentrale Methode.
    Jeden Thread Aufruf wird über diese Methode geschehen

    @Schlangenmensch

    while(isRunning());  //Da du nach dem Thread start() auf die Beendigung wartest, solltest du das auch nicht brauchen.
    

    Wie kritisch, wenn ich das so lasse?



  • Kritisch sollte das isRunning() nicht sein. Aber dient halt nicht der Übersichtlichkeit. Code der nicht gebraucht wird, kann gestrichen werden.

    Und wenn es darum geht Fehler zu finden, ist es manchmal eine gute Idee den Code auf das Nötigste zu reduzieren.

    Was passiert denn, wenn du nicht start() aufrufst, sondern direkt run(). Dann hast du keinen extra Thread, sondern einen einfachen sequentiellen Programmablauf (entsprechende Threadbedingte Codezeilen auskommentieren). Damit kannst du zumindest schon mal feststellen, ob dein Fehler tatsächlich im Multithreading Teil liegt.



  • Schlangenmensch schrieb:

    Kritisch sollte das isRunning() nicht sein. Aber dient halt nicht der Übersichtlichkeit. Code der nicht gebraucht wird, kann gestrichen werden.

    Und wenn es darum geht Fehler zu finden, ist es manchmal eine gute Idee den Code auf das Nötigste zu reduzieren.

    Was passiert denn, wenn du nicht start() aufrufst, sondern direkt run(). Dann hast du keinen extra Thread, sondern einen einfachen sequentiellen Programmablauf (entsprechende Threadbedingte Codezeilen auskommentieren). Damit kannst du zumindest schon mal feststellen, ob dein Fehler tatsächlich im Multithreading Teil liegt.

    SW bleibt hängend, wenn ich :

    //start();
    this->run();
    


  • Dann kannst du erstmal ganz klassich debuggen.

    Was gibt dir denn die Aufrufliste in VS aus? Interessant sind vor allem die letzten Aufrufe aus deinem Code?



  • Ich versuche hier wann und wie der oben genannten Fehler auftritt:
    ....
    Im laufe das Programm mache ich folgende:

    If(eine bestimmte Bedingung)
    {
    	VisaAgilent reference(......);
    	reference.ExecuteRUNControl(); // Task wird erfolgreich geschlossen
    }
    

    // wenn diesen Block "{}" verlassen wird, dann wird der Destruktor gerufen und der so ausieht:

    VisaAgilent::~VisaAgilent()
    {
        while(isRunning());
    
        this->Close(m_iTimeoutClose);
    
        while(isRunning());
    
        if (this->Execute("DeleteObject", 0, 0, 0) != enRspOK)
        {
            throw(QString("Destructor TcpSocket Delete memory error"));
        }
    
        while(isRunning());
    }
    

    diese wiederum ruft der close Methode, die so aussieht:

    bool VisaAgilent::Close(const int iTimeout_p)
    {
        bool boRet_l = true;
    
        while(isRunning());
    
        if (this->Execute("CloseConnection", 500, iTimeout_p, 1000) != enRspOK)
        {
            throw(QString("Close Connection error"));
        }
    
        if (m_boDebug)
        {
            throw(QString("Tcp Socket is closed"));
        }
    
        while(isRunning());
    
        return boRet_l;
    }
    

    dies ruft wieder

    Execute(...)
    

    Methode und genau in diesem Methode
    nach der

    start()
    

    Aufruf kracht die SW, da die

    run()
    

    Methode nicht aufgerufen wird was normaleweise nicht der Fall ist.
    Also

    run()
    

    muss immer automatische nach dem Aufruf von

    start()
    

    folgen.



  • Was ich grade sehe, du wirfst Exceptions im Destruktor und du hast auf VS 2015 umgestellt. VS 2015 kompiliert nach C++11 Standard.
    Danach ist jeder Destruktor impliziet noexcept. Wenn du doch Exceptions aus deinem Destruktor werfen willst musst du den Destruktor mit noexcept(false) deklarieren. Also in der Klassendeklaration:

    ~VisaAgilent() noexcept(false);
    

    Edit: Freitag Nachmittag hab ich's offensichtlich nicht mehr so mit dem Tippen.



  • Schlangenmensch schrieb:

    [code="cpp"]
    ~VisaAgilent() noexcept(false);
    [/code

    Wenn der Code so verändere werden, dann bekomme ich die Fehlermeldung:
    Error C2694



  • Hm, dass wird wahrscheinlich daran liegen, dass der Basisklassen Destruktor "noexcept" ist.

    'override': overriding virtual function has less restrictive exception specification than base class virtual member function 'base'

    Quelle: https://msdn.microsoft.com/en-us/library/e4x95xf8.aspx

    An deiner Stelle, würde ich die Exception im Destruktor vermeiden. Das kann auch so unbeabsichtigte Folgen haben, z.B. wenn der Destruktor im Folge einer anderen Exception aufgerufen wird, wird std::terminate aufgerufen und das Programm wird beendet.

    Hier dazu aus der Referenz:

    As any other function, a destructor may terminate by throwing an exception (this usually requires it to be explicitly declared noexcept(false)) (since C++11), however if this destructor happens to be called during stack unwinding, std::terminate is called instead.

    Although std::uncaught_exception may sometimes be used to detect stack unwinding in progress, it is generally considered bad practice to allow any destructor to terminate by throwing an exception. This functionality is nevertheless used by some libraries, such as SOCI and Galera 3, which rely on the ability of the destructors of nameless temporaries to throw exceptions at the end of the full expression that constructs the temporary.

    Quelle: http://en.cppreference.com/w/cpp/language/destructor

    Für dich eventuell auch interessant:
    http://denisbider.blogspot.de/2015/07/exceptions-in-destructors-and-visual.html



  • Hi,
    ich glaube ich bin auf eine heisse Spur.
    Der Thread wird irgendwie nicht richtig aufgeraumt und das ist glaube ich das Problem.

    Dazu habe ich eine technische Frage:
    Sei folgende:
    Header File:

    ...
    QTcpSocket *m_pTcpSctCtrl;
    

    Cpp File:

    ....
    m_pTcpSctCtrl = (QTcpSocket *)new QTcpSocket;
    

    Darf ich so schreiben?
    danke


  • Mod

    Es ist eine ganz schlechte Idee, Dinge in Headern zu definieren. Dann hat jeder, der den Header benutzt, seine eigene Instanz der dort definierten Objekte.



  • Hast du denn deinen Aufräum Code mal aus dem Destruktor genommen und in eine "CleanUp" Funktion o.ä. gepackt? Ich denke, dass sollte dir schon weiter helfen.

    Zu deiner Frage: Warum willst du das so schreiben?

    Du deklarierst einen Pointer im Header. In der cpp erstellst du ein Objekt auf dem Heap, auf das der Pointer zeigen soll. Und dann konvertierst du den Pointer, den dir new zurück gibt zu einem Pointer....

    Was spricht denn gegen:

    m_pTcpSctCtrl = new QTcpSocket;
    

    Wenn du das so machst, dass delete nicht vergessen. Bessere Idee wäre der Einsatz eines Smartpointers.


  • Mod

    Schlangenmensch schrieb:

    Bessere Idee wäre der Einsatz eines Smartpointers.

    Hat Qt nicht so einen komischen, internen GC? Irgendwie habe ich jedenfalls im Hinterkopf, dass sich Qt nicht gut mit dem üblichen Ressourcenmodell von C++ verträgt.



  • SeppJ schrieb:

    Hat Qt nicht so einen komischen, internen GC? Irgendwie habe ich jedenfalls im Hinterkopf, dass sich Qt nicht gut mit dem üblichen Ressourcenmodell von C++ verträgt.

    Ja, da war was. Aber wenn ich das richtig im Kopf habe, bezieht sich das vor allem auf erstellen von Fenstern. Da gibt man immer einen Parent mit, der dann den Besitz übernimmt.

    Davon abgesehen habe ich ja nicht std::unique_ptr sondern allgemein Smart Pointer gesagt 😉 QT verfügt über eigene Smart Pointer Implementationen, die man hoffentlich auch mit QT Objekten benutzen kann.



  • SeppJ schrieb:

    Schlangenmensch schrieb:

    Bessere Idee wäre der Einsatz eines Smartpointers.

    Hat Qt nicht so einen komischen, internen GC? Irgendwie habe ich jedenfalls im Hinterkopf, dass sich Qt nicht gut mit dem üblichen Ressourcenmodell von C++ verträgt.

    Ich arbeite mich auch gerade in Qt ein. Entweder man erzeugt die Objekte gleich mit Parent, damit das erzeugende Objekt den Besitz (und die Freigabe) übernimmt.

    Edit: Der Parent muss vom Typ QObject sein.

    m_pTcpSctCtrl = new QTcpSocket(this)
    

    oder das erzeugte Objekt wird an ein anderes Object übergeben, dass den Besitz übernimmt, z.B.

    ui->workspace->addWidget(new CustomerList);
    

    addWidget übergibt den Besitz des parentlosen CustomerList-Objektes an workspace.



  • Hallo Zusammen,

    ich habe es folgende in der

    run()
    

    Methode:

    m_pTcpSctCtrl = new QTcpSocket(this);
    

    angepasst.

    Es hat aber auch nichts gebracht.

    Ich habe am anfang gedacht, dass das Problem in der Destruktor was wirklich nicht der Fall ist.

    wenn ich folgende schreibe:
    [code="cpp"]
    If(eine bestimmte Bedingung)
    {
    VisaAgilent reference(......);
    reference.ExecuteRUNControl(); // Task wird erfolgreich geschlossen
    reference.ExecuteRUNControl(); // Task wird nicht erfolgreich abgeschlossen
    }[/code]

    das heisst Problem tritt auf bei jede zweiten beliebige Aufruf von Methoden der Object

    VisaAgilent
    

    .

    --> das deutet darauf hin, dass der Thread irgendwie unsauber implemntiert ist.



  • Und was macht ExecuteRUNControl()? Die Funktion kam in den Code Ausschnitten, die du bisher gepostet hast nicht vor. Raten macht keinen Spaß!

    Was hast du denn von den Anmerkungen bisher umgesetzt? Hast du die Exception aus dem Destruktor entfernt? Selbst wenn dein Programm wo anders abstürtzt ist das so falsch!



  • Schlangenmensch schrieb:

    Und was macht ExecuteRUNControl()? Die Funktion kam in den Code Ausschnitten, die du bisher gepostet hast nicht vor. Raten macht keinen Spaß!

    Du hast recht Sorry:

    void VisaAgilent::ExecuteRunControl(void)
    {
    	this->Execute("Run \n",200,1000,0);
    }
    

    Schlangenmensch schrieb:

    Was hast du denn von den Anmerkungen bisher umgesetzt?

    alle vorgeschlagene Erweiterungen habe ich umgesetzt.

    1. Entfernung der Exception aus der Destruktor
    m_pTcpSctCtrl = (QTcpSocket *)new QTcpSocket;
    

    zu

    m_pTcpSctCtrl = new QTcpSocket(this);
    

    umgeschrieben.

    Schlangenmensch schrieb:

    Hast du die Exception aus dem Destruktor entfernt?
    Selbst wenn dein Programm wo anders abstürtzt ist das so falsch!

    ja

    Könnte es sein, dass bei der Qt5.7 bzw. QTcpSocket einen Bug hat?

    Wie gesagt: ich habe dieses Projekt auch unter Visual studio 2008 mit Qt 4.8 Plug-In und dort laufen beide Versionen Debug/Release einwandfrei



  • Ich halte es für unwahrscheinlich, das Qt ein Bug hat, kann es aber nicht ausschließen.

    Bei dem Aufruf von welcher Codezeile genau stürtzt dein Programm ab?

    Was für ein Wert hat "m_boDebug"?

    Dann noch ein paar kleine Anmerkungen:

    Du übergibst deinem TCP Socket einen This Pointer. Der Pointer zeigt auf ein Objekt das von QThread erbt. QThread erbt von QObject, daher solltest du das nicht manuell löschen müssen.

    QTCPSocket::write kannst du direkt ein QByteArray übergeben. .data() ist nicht nötig (). Wenn sollte auch constData() verwendet werden.

    readAll(): hat keine Möglichkeit Fehler zu reporten. Eventuell wäre es besser eine normale "read()" Funktion zu benutzen, die die Anzahl an gelesenen Bytes zurück gibt und -1 bei Fehlern.



  • Schlangenmensch schrieb:

    Ich halte es für unwahrscheinlich, das Qt ein Bug hat, kann es aber nicht ausschließen.

    Bei dem Aufruf von welcher Codezeile genau stürtzt dein Programm ab?

    genau bei diese Zeile

    start();
    

    in diese FKT:

    VisaAgilent::t_enRspType VisaAgilent::Execute(const char *strCmd_p, const int iWaitResponse_p, const int iTimeout_p, const int iRspDelayed_p)
    {
        CAgilentLan::t_enRspType enRetVal_l = enRspOffline;
    
        if (!isRunning())
        {
            m_ByteArrayRead.clear();
    
            m_ByteArrayWrite.clear();
            m_ByteArrayWrite.append(strCmd_p);
    
            m_iWaitResponse = iWaitResponse_p;
            m_iTimeout = iTimeout_p;
            m_iResponseDelayed = iRspDelayed_p;
    
            start();
    
            m_MtxProcess.lock();
            m_WaitCondProcess.wait(&m_MtxProcess,-1);
            m_MtxProcess.unlock();// Prozess wird immer freigegeben
    
            enRetVal_l = this->m_enRetVal;
        }
        else
        {
            enRetVal_l = enRspError;
        }
    
        while(isRunning());
    
        return enRetVal_l;
    }
    

    Was für ein Wert hat "m_boDebug"?

    false
    

    Es ist als defaultValue bei der Konstructor:

    Header File:

    CAgilentLan(QString strIpAdress_p, int iTimeout_p, bool boSimulate_p = false, bool boDebug_p = false);
    

    Schlangenmensch schrieb:

    Dann noch ein paar kleine Anmerkungen:

    Du übergibst deinem TCP Socket einen This Pointer. Der Pointer zeigt auf ein Objekt das von QThread erbt. QThread erbt von QObject, daher solltest du das nicht manuell löschen müssen.

    Ist das eine Frage?

    Schlangenmensch schrieb:

    QTCPSocket::write kannst du direkt ein QByteArray übergeben. .data() ist nicht nötig (). Wenn sollte auch constData() verwendet werden.

    danke für den Hinweis schon geschehen

    Schlangenmensch schrieb:

    readAll(): hat keine Möglichkeit Fehler zu reporten. Eventuell wäre es besser eine normale "read()" Funktion zu benutzen, die die Anzahl an gelesenen Bytes zurück gibt und -1 bei Fehlern.

    Beim read brauche ich eine übergabe Parameter

    QByteArray read(qint64 maxlen);
    

    --> und die habe ich nit



  • Ich habe eher an: qint64 QIODevice::read(char *data, qint64 maxSize) gedacht.

    Überleg dir was für maxSize passt und lese so lange, bis keine Daten mehr im Stream sind. Also read "0" zurück gibt.

    Wenn du befürchtest, dass der Fehler im TCP Bereich liegt, würde ich nochmal den Multithreading part, raus nehmen. (nicht start() aufrufen, sondern direkt die run()). Und dann schauen wo, er in der run() rausfliegt. Dann kannst du auch mit dem Debugger durch steppen.

    Eine andere Möglichkeit wäre, die TCP Sachen mal auszukommentieren und testen ob es dann läuft (auch wenn nichts produktives passiert). Dann solange wieder einkommentieren, bis der Fehler lokalisiert ist.

    Saheb schrieb:

    Ist das eine Frage?

    Ja, das war eine Frage. Ich bin mir bei der Speicherverwaltung in QT nicht 100% sicher. Aber sonst knallst du mit einem double delete raus, das merkst du dann schon, wenn es nicht geht.

    Edit: readAll ist wahrscheinlich einfacher. Da kannst halt nur nicht zwischen "keine Daten da" und "Fehler" unterscheiden.


Anmelden zum Antworten