Use Qt thread correctly



  • How to use qthread with mutex?
    Here is my old code:
    Header:

    class QTcpSocket;
    
    class CAgilentLan : public QThread
    {
    
    public:
    
    	typedef enum 
    	{
    		enRspTimeout = -2, 
    		enRspOffline,
    		enRspOK,
    		enRspError
    	} t_enRspType ;
    
    
    	CAgilentLan(QString strIpAdress_p, int iTimeout_p, bool boSimulate_p=false, bool boDebug_p=false);
    	~CAgilentLan();
    
    	// High-Level Funktionen
    	QByteArray ExecuteGetScreenshot(void);
    	void ExecuteSaveScreenshot(QString &strPathFileName_p, const char *strFormat_p);
    	void ExecuteSettingsSave(unsigned char ucRegisterNo_p);
    	void ExecuteSettingsRecall(unsigned char ucRegisterNo_p);
    	double ExecuteQuickMeasure(unsigned char ucChannel_p, char *pchType_p);
    	double ExecuteStatMeasure(char *pchType_p, bool boTrigger_p);
    	void ExecuteResetMeasurementStatistics(void);
    
    	bool Open(const QString &strIpAdress_p, const int iTimeout_p);
    	bool Close(const int iTimeout_p);
    	t_enRspType Execute(const char *strCmd_p, const int iWaitResponse_p, const int iTimeout_p, const int iRspDelayed_p);
    	QByteArray GetLastResponse(void);
    
    	t_enRspType ExecuteSimulated(const char *strCmd_p);
    	QString GetAgilentIdentifikation();
    
    	...
    
    protected:
    	void run();
    
    private:
    	bool m_boDebug;
    	bool m_boSimulate;
    	
    	QMutex m_MtxProcess;
    	QMutex m_MtxResponse;
    
    	QWaitCondition m_WaitCondProcess;
    	QByteArray m_ByteArrayWrite;
    	QByteArray m_ByteArrayRead;
    
    	QByteArray m_IDN_AgilentIdentification;
    	
    	//Hilfsvariable
    	double m_SDDevPeriodeA ;
    	double m_SDDevDCA;
    	double m_SDDevDCB;
    	double m_SDDevWidthZ;
    
    	double m_OZiSDDevPeriodeA;
    	double m_OZiSDDevDCA;
    	double m_OZiSDDevDCB;
    	double m_OZiSDDevWidthZ;
    
    	double m_OZiMeanPeriodeA;
    	double m_OZiMeanDCA;
    	double m_OZiMeanDCB;
    	double m_OZiMeanWidthZ;
    	
    	QByteArray m_ByteSTDD;
    	QByteArray m_ByteMean;
    	QStringList m_ListSTDDev;
    	QStringList m_ListMean;
    
    	QTcpSocket *m_pTcpSctCtrl;
    	
    	QString m_strCtrlIP;
    	int m_iTimeoutClose;
    	int m_iTimeout;
    	int m_iResponseDelayed;
    	int m_iWaitResponse;
    
    	t_enRspType m_enRetVal;
    };
    
    

    Cpp File:

    CAgilentLan::CAgilentLan(QString strIpAdress_p, int iTimeout_p, bool boSimulate_p, bool boDebug_p):m_SDDevPeriodeA(0), m_SDDevDCA(0),m_SDDevDCB(0),m_SDDevWidthZ(0)
    {
    //	boSimulate_p = false;
    	
    	m_boDebug = boDebug_p;
    	m_boSimulate = boSimulate_p;
    
    	m_enRetVal = enRspOffline;
    	m_strCtrlIP = QString("");
    	m_iTimeout = 0;
    	m_iTimeoutClose = iTimeout_p;
    	if (this->Execute("CreateObject", 0, 0, 0) != enRspOK)
    	{
    		throw(QString("Error AgilentLan.CPP/Constructor TcpSocket Create memory error"));
    	}
    
    	this->Open(strIpAdress_p, iTimeout_p);
    }
    
    CAgilentLan::~CAgilentLan()
    {
    	while(isRunning());
    
    	this->Close(m_iTimeoutClose);
    
    	while(isRunning());
    	
    	if (this->Execute("DeleteObject", 0, 0, 0) != enRspOK)
    	{
    		throw(QString("Error AgilentLan.CPP/Destructor TcpSocket Delete memory error"));
    	}
    
    	
    	while(isRunning());
    }
    bool CAgilentLan::Open(const QString &strCtrlIP_p, const int iTimeout_p)
    {
    	bool boRet_l = true;
    
    	m_strCtrlIP = strCtrlIP_p;
    		
    	if (this->Execute("OpenConnection", 0, iTimeout_p, 0) != enRspOK)
    	{
    		throw(QString("Error AgilentLan.CPP/Open TcpSocket Open Connection error"));
    	}
    	
    	if (m_boDebug)
    	{
    		throw(QString("Tcp Socket is open"));
    	}
    
    	return boRet_l;
    }
    
    bool CAgilentLan::Close(const int iTimeout_p)
    {
    	bool boRet_l = true;
    
    	while(isRunning());
    
    	if (this->Execute("CloseConnection", 0, iTimeout_p, 0) != enRspOK)
    	{
    		throw(QString("Error AgilentLan.CPP/Close Connection error"));
    	}
    	
    	if (m_boDebug)
    	{
    		throw(QString("Tcp Socket is closed"));
    	}
    
    	while(isRunning());
    
    	return boRet_l;
    }
    
    
    CAgilentLan::t_enRspType CAgilentLan::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();
    	
    		enRetVal_l = this->m_enRetVal;
    	}
    	else
    	{
    		enRetVal_l = enRspError;
    	}
    	
    	while(isRunning());
    	
    	return enRetVal_l;
    }
    
    QByteArray CAgilentLan::GetLastResponse(void)
    {
    	QByteArray ay_l;
    
    	m_MtxResponse.lock();
    	ay_l = m_ByteArrayRead;
    	m_MtxResponse.unlock();
    
    	return ay_l;
    }
    void CAgilentLan::run()
    {
    	bool boRun_l = true;
    	bool boSent_l = false;
    
    	const char *pStrCmd_l = NULL;
    	const char *pStrRsp_l = NULL;
    
    	m_enRetVal = enRspError;
    
    	if (strcmp(m_ByteArrayWrite.data(),"CreateObject")==0)
    	{
    		if (this->m_boSimulate == true)
    		{
    			m_enRetVal = enRspOK;
    		}
    		else
    		{
    			m_pTcpSctCtrl = (QTcpSocket *)new QTcpSocket;
    			if (m_pTcpSctCtrl != NULL)
    			{
    				m_enRetVal = enRspOK;
    			}
    		}
    
    		boRun_l = false;
    	}
    
    	if (strcmp(m_ByteArrayWrite.data(),"DeleteObject")==0)
    	{
    		if (this->m_boSimulate == true)
    		{
    		}
    		else
    		{
    			if (m_pTcpSctCtrl != NULL)
    			{
    				delete m_pTcpSctCtrl;
    			}
    		}
    
    		m_enRetVal = enRspOK;
    		boRun_l = false;
    	}
    
    	if (strcmp(m_ByteArrayWrite.data(),"OpenConnection")==0)
    	{
    		if (this->m_boSimulate == true)
    		{
    			m_enRetVal = enRspOK;
    		}
    		else
    		{
    			m_pTcpSctCtrl->connectToHost(m_strCtrlIP,5025);
    			if (m_pTcpSctCtrl->waitForConnected(m_iTimeout) == true)
    			{
    				m_enRetVal = enRspOK;
    			}
    		}
    		
    		boRun_l = false;
    	}
    
    	if (strcmp(m_ByteArrayWrite.data(),"CloseConnection")==0)
    	{
    		if (this->m_boSimulate == true)
    		{
    			m_enRetVal = enRspOK;
    		}
    		else
    		{
    			m_pTcpSctCtrl->disconnectFromHost();
    			if ((m_pTcpSctCtrl->state() == QAbstractSocket::UnconnectedState) || (m_pTcpSctCtrl->waitForDisconnected(m_iTimeout)))
    			{
    				m_enRetVal = enRspOK;
    			}
    		}
    		
    		boRun_l = false;
    	}
    
    	int iTimeout_l = m_iTimeout;
    	
    	while (boRun_l && (!this->m_boSimulate))
    	{
     		if (boSent_l == false)
    		{
    			boSent_l = true;
    			// Kommando absetzen
    			m_pTcpSctCtrl->write(m_ByteArrayWrite.data(),m_ByteArrayWrite.size());
    			// Auf Antwort warten
    			if (m_iWaitResponse >= 0)
    			{
    				QThread::msleep(m_iWaitResponse);
    			}
    			else
    			{
    				boRun_l = false;
    			}
    		}
    		
    		// Anwort auf Kommando abwarten	
    		if ((m_pTcpSctCtrl->bytesAvailable() > 0) && (boRun_l == true))
    		{
    			m_MtxResponse.lock();
    
    			m_ByteArrayRead.append(m_pTcpSctCtrl->readAll());
    			
    			if (m_boDebug)
    			{
    				throw(QString(m_ByteArrayRead.data()));
    			}
    
    			m_MtxResponse.unlock();
    
    			iTimeout_l = m_iTimeout;
    //			iTimeout_l = m_iWaitResponse;
    		}
    		else
    		{
    			if (m_pTcpSctCtrl->waitForReadyRead(iTimeout_l) == false)
    			{
    				m_MtxResponse.lock();
    
    				if (m_ByteArrayRead.size() == 0)
    				{
    					if (m_boDebug)
    					{
    						throw(QString("AgilentLan Timeout"));
    					}
    					m_enRetVal = enRspTimeout;
    				}
    				else
    				{
    					m_enRetVal = enRspOK;
    				}
    
    				m_MtxResponse.unlock();
    				
    				boRun_l = false;					
    			}
    		}
    	}
    	
    	QThread::msleep(m_iResponseDelayed);
    	
    	QMutexLocker locker(&m_MtxProcess);
    
    	m_WaitCondProcess.wakeOne();
    
    }
    

    This code section I have adapted to the following:

    class CAgilentLan : public QObject
    {
    	Q_OBJECT
     
    public:
     ...
        CAgilentLan(QString strIpAdress_p, int iTimeout_p, bool boSimulate_p=false, bool boDebug_p=false);
        ~CAgilentLan();
     
    ...
        t_enRspType Execute(const char *strCmd_p, const int iWaitResponse_p, const int iTimeout_p, const int iRspDelayed_p);
     ..
     
    public slots:
       void init();
       void openCommunikation();
        void AgilentStart();
    signals:
    void finished();
    ....
     
    
    };
    

    what is wrong?


  • Moderators

    @Galilio Is this a puzzle and we need to find out what is not working?
    Why don't you say what is not working?


  • Moderators

    @Galilio This can be simplified:

    QByteArray CAgilentLan::GetLastResponse(void)
    {
    	QByteArray ay_l;
    
    	m_MtxResponse.lock();
    	ay_l = m_ByteArrayRead;
    	m_MtxResponse.unlock();
    
    	return ay_l;
    }
    

    to

    QByteArray CAgilentLan::GetLastResponse(void)
    {
    	QMutexLocker(m_MtxResponse);
    	return m_ByteArrayRead;
    }
    


  • At a class where I have the object "CAgilentLan"
    Calls I write in the contructor the following:

    //CAgilentLan* m_pvAgilentWorker; 
    m_pvWorkerThread = new QThread();
    m_pvAgilentWorker = new CAgilentLan(settings_l.strfuGetIP_DSO(), 500, settings_l.bofuGetSimulate());
    m_pvAgilentWorker->moveToThread(m_pvWorkerThread);
    connect(m_pvWorkerThread, &QThread::started, m_pvAgilentWorker, &CAgilentLan::agilentStart);
       
    connect(m_pvWorkerThread, &QThread::finished, m_pvWorkerThread, &QThread::deleteLater);
    connect(m_pvWorkerThread, &QThread::finished, m_pvWorkerThread, &CAgilentLan::deleteLater);
    m_pvWorkerThread->start();
    

    This is the error message:

    ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 4c19f68. Receiver '' (of type 'QNativeSocketEngine') was created in thread 4c582e0", file kernel\qcoreapplication.cpp, line 541
    


  • @jsulm

    QByteArray CAgilentLan::GetLastResponse(void)
    {
        QMutexLocker(m_MtxResponse);
        return m_ByteArrayRead;
    }
    

    Won't that temporary QMutexLocker need a name? Otherwise it will be deconstructed as a temporary object at the end of the first statement and the return won't be locked properly.


  • Moderators

    @corruptedsyntax Sure, thanks for pointing that out :-)

    QByteArray CAgilentLan::GetLastResponse(void)
    {
        QMutexLocker mutexLocker(m_MtxResponse);
        return m_ByteArrayRead;
    }
    


  • @jsulm
    Hi,
    So is correct:

    QByteArray CAgilentLan::GetLastResponse(void)
    {
        QMutexLocker mutexLocker(&m_MtxResponse);
        return m_ByteArrayRead;
    }
    

  • Moderators

    @Galilio yes



  • Hi,
    How can I avoid this error?



  • @jsulm
    Problem occurs when the application is exited.
    The Destructor is then called, which looks like this:

    CAgilentLan::~CAgilentLan()
    {
    	this->Close(GetiTimeOutClose());
    
    	if (this->Execute("DeleteObject", 0, 0, 0) != enRspOK)
    	{
    		throw(QString("Error AgilentLan.CPP/Destructor TcpSocket Delete memory error"));
    	}
    }
    

    And right here is the problem:

    GetTcpSocket()->disconnectFromHost();
    

  • Moderators

    @Galilio What error? What problem? Can you be more precise?
    You should not throw exceptions from destructors.



  • @jsulm
    The TcpSocket connection can not be closed
    Error is:

    ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread dc02d0. Receiver '' (of type 'QNativeSocketEngine') was created in thread 4912418", file kernel\qcoreapplication.cpp, line 541
    
    

  • Moderators

    @Galilio You are doing something wrong with your threads



  • @jsulm
    Yes but what?
    My QThread looks like this:

    m_pvWorkerThread = new QThread();
    m_pvAgilentWorker = new CAgilentLan(settings_l.strfuGetIP_DSO(), 500, settings_l.bofuGetSimulate());
    m_pvAgilentWorker->moveToThread(m_pvWorkerThread);
    connect(m_pvWorkerThread, &QThread::started, m_pvAgilentWorker, &CAgilentLan::agilentStart);
       
    connect(m_pvWorkerThread, &QThread::finished, m_pvWorkerThread, &QThread::deleteLater);
    connect(m_pvWorkerThread, &QThread::finished, m_pvWorkerThread, &CAgilentLan::deleteLater);
    m_pvWorkerThread->start();
    

  • Moderators

    @Galilio Sorry, currently I have no time to analyse your code.
    You should read: https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.