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



  • Schlangenmensch schrieb:

    Apropos Synchronisation... Was passiert denn wenn

    m_WaitCondProcess.wakeOne();
    

    aufgerufen wird bevor

    m_WaitCondProcess.wait(&m_MtxProcess,-1);
    

    aufgerufen wurde.

    Tread wird nie beendet also SW bleibt hängen



  • Warum nimmst du nichst das normale wait(). Dann kannst du dir das wakeOne() sparen.



  • Schlangenmensch schrieb:

    Warum nimmst du nichst das normale wait(). Dann kannst du dir das wakeOne() sparen.

    Wenn ich das so implementiere dann bleibt die Application auch hängend.
    Also Thread wird ne beendet.



  • Wenn du wait() in deine Execute hinzufügst

    VisaAgilent::t_enRspType VisaAgilent::Execute(const char *strCmd_p, const int iWaitResponse_p, const int iTimeout_p, const int iRspDelayed_p)
    {
        VisaAgilent::t_enRspType enRetVal_l = enRspOffline;
    
        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
        {
            m_ByteArrayRead.clear();
    
            m_ByteArrayWrite.clear();
            m_ByteArrayWrite.append(strCmd_p);
    
            m_iWaitResponse = iWaitResponse_p;
            m_iTimeout = iTimeout_p;
            m_iResponseDelayed = iRspDelayed_p;
    
            start();
    
            this->wait(); 
            //oder 
            if(!this->isFinished())
               this->wait();           
    
            enRetVal_l = this->m_enRetVal;
        }
        else
        {
            enRetVal_l = enRspError;
        }
    
        while(isRunning());  //Da du nach dem Thread start() auf die Beendigung wartest, solltest du das auch nicht brauchen.
    
        return enRetVal_l;
    }
    

    und in run()

    QThread::msleep(m_iResponseDelayed);
    
        QMutexLocker locker(&m_MtxProcess);
    
        m_WaitCondProcess.wakeOne();
    

    entfernst, beendet sich deine Software nicht?

    Edit: Was ich eigentlich schreiben wollte, wenn du dein Source Code so postest, dass ich den per Copy&Paste ans laufen bringen kann, probiere ich das heute abend mal aus.

    Edit2: Insbesondere habe ich keine Lust mir die ganzen Includes raus zu suchen.



  • Schlangenmensch schrieb:

    .... beendet sich deine Software nicht?

    Es tritt die gleiche Fehlermeldung



  • @ Schlangenmensch

    Es gibt so viele Abhängigkeiten, was das Copy&Paste schwierige machen.
    Dazu wir eine Hardware gebraucht sonst geht es nicht.



  • @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.


Anmelden zum Antworten