现在的位置: 首页 > 综合 > 正文

QThread使用

2018年03月29日 ⁄ 综合 ⁄ 共 4533字 ⁄ 字号 评论关闭

QT assistant 中通过QThread创建子线程有两种方法。

方法1:

class Worker : public QObject
 {
     Q_OBJECT
     QThread workerThread;

 public slots:
     void doWork(const QString &parameter) {
         // ...
         emit resultReady(result);
     }

 signals:
     void resultReady(const QString &result);
 };

 class Controller : public QObject
 {
     Q_OBJECT
     QThread workerThread;
 public:
     Controller() {
         Worker *worker = new Worker;
         worker->moveToThread(&workerThread);
         connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
         connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString)));
         connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
         workerThread.start();
     }
     ~Controller() {
         workerThread.quit();
         workerThread.wait();
     }
 public slots:
     void handleResults(const QString &);
 signals:
     void operate(const QString &);
 };

方法2:

class WorkerThread : public QThread
 {
     Q_OBJECT
     void run() {
         QString result;
         /* expensive or blocking operation  */
         emit resultReady(result);
     }
 signals:
     void resultReady(const QString &s);
 };

 void MyObject::startWorkInAThread()
 {
     WorkerThread *workerThread = new WorkerThread(this);
     connect(workerThread, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
     connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
     workerThread->start();
 }

void QObject::deleteLater () [slot]

Schedules this object for deletion.

The object will be deleted when control returns to the event loop. If the event loop is not running when this function is called (e.g. deleteLater() is called on an object beforeQCoreApplication::exec()),
the object will be deleted once the event loop is started.
If deleteLater() is called after the main event loop has stopped, the object will not be deleted
. Since Qt 4.8, if deleteLater() is called on an object that lives in a thread with no running event loop, the object will be destroyed when the thread finishes.

Note that entering and leaving a new event loop (e.g., by opening a modal dialog) will not perform the deferred deletion; for the object to be deleted, the control must return to the event loop from which deleteLater()
was called.

Note: It is safe to call this function more than once; when the first deferred deletion event is delivered, any pending events for the object are removed from the event queue.

我的工程中用了第二种方法

WorkThread.hpp:

class WorkerThread : public QThread
{
	Q_OBJECT

public:
	typedef enum
	{
		Thread_Invalid,
		Create_Thread_Failed,
		Thread_Finished
	} Thread_Result_EN;

	WorkerThread(const QString &strCmd, const QString &strLog) : \
		 m_enState(Thread_Invalid),m_strCMD(strCmd),m_strLogFile(strLog){}
	
	Thread_Result_EN currentState(void){return m_enState;}

protected:
	virtual void run();

private:
	Thread_Result_EN m_enState;
	QString m_strCMD, m_strLogFile;

Q_SIGNALS:
	void resultReady(Thread_Result_EN enResult);
};

WorkThread.cpp:

void WorkerThread::run()
{
	std::string strCmd = std::string((const char*)(m_strCMD.toLocal8Bit()));
	std::string strLog = std::string((const char*)(m_strLogFile.toLocal8Bit()));

#ifdef WIN32
	STARTUPINFO sInfo;
	PROCESS_INFORMATION pInfo;

	ZeroMemory(&sInfo, sizeof(STARTUPINFO));
	ZeroMemory(&pInfo, sizeof(PROCESS_INFORMATION));
	sInfo.cb = sizeof(STARTUPINFO);

	sInfo.dwFlags = STARTF_USESTDHANDLES;
	sInfo.wShowWindow = SW_HIDE;

	SECURITY_ATTRIBUTES saAttr; 
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
	saAttr.bInheritHandle = TRUE; 
	saAttr.lpSecurityDescriptor = NULL; 

	HANDLE hrFile, hwFile;
	if(!CreatePipe(&hrFile, &hwFile,         
		&saAttr, NULL))
	{
		m_enState = Create_Thread_Failed;
		emit resultReady(Create_Thread_Failed);
		return;
	}

	HANDLE hStdO = CreateFileA(strLog.c_str(),
		FILE_APPEND_DATA,             
		FILE_SHARE_WRITE | FILE_SHARE_READ,
		&saAttr,                     
		CREATE_ALWAYS,           
		FILE_ATTRIBUTE_NORMAL,   
		NULL);                   

	if (INVALID_HANDLE_VALUE == hStdO)
	{
		m_enState = Create_Thread_Failed;
		emit resultReady(Create_Thread_Failed);
		return;
	}

	sInfo.hStdOutput = hStdO;
	sInfo.hStdError = hStdO;

	BOOL bRetVal = CreateProcessA(NULL,
		(LPSTR)strCmd.c_str(),
		NULL,
		NULL,
		TRUE,
		CREATE_NO_WINDOW,
		NULL,
		NULL,
		(LPSTARTUPINFOA)&sInfo,
		&pInfo
		);

	if(!bRetVal)
	{
		m_enState = Create_Thread_Failed;
		emit resultReady(Create_Thread_Failed);
		return;
	}

	WaitForSingleObject(pInfo.hProcess, INFINITE);
	CloseHandle(pInfo.hProcess);
	CloseHandle(pInfo.hThread);

#else
	string strrun = strCmd + " > " + strLog + " 2>&1";
	system(strrun.c_str());
#endif

	m_enState = Thread_Finished;
	emit resultReady(Thread_Finished);
}

main.cpp:

    WorkerThread wthEvtSetup("perl \"./event_setup_generator.pl\"", "./perl.log");
    //connect(&wthEvtSetup, SIGNAL(finished()), this, SLOT(deleteLater()));
#if 0
    connect(&wthEvtSetup, SIGNAL(resultReady(WorkerThread::Thread_Result_EN)), this, SLOT(_EventSetupFinished(WorkerThread::Thread_Result_EN)));
    wthEvtSetup.start();
    wthEvtSetup.wait();
#else
    wthEvtSetup.start();
    wthEvtSetup.wait();

    QMessageBox::warning(this, QString("run DebugModule"), QString("process create failed!"));
    _EventSetupFinished(wthEvtSetup.currentState());
#endif

加上被注释的那一句,QMessageBox就会coredump,具体原因应该是deleteLater()导致的。

但这里wthEvtSetup的run()中发出的信号resultReady()却没能触发_EventSetupFinished(),不明白为什么?

抱歉!评论已关闭.