爲了在一個單獨的線程中創建一個Qt事件循環,在由Java編寫的主應用程序調用的DLL中創建一個Qt事件循環,我做了以下工作,根據建議,我讀here,它的工作原理相當不錯:在QThread中的QCoreApplication上調用quit()時發生錯誤
// Define a global namespace. We need to do this because the parameters
// passed to QCoreApplication must have a lifetime exceeding that of the
// QCoreApplication object
namespace ToolThreadGlobal
{
static int argc = 1;
static char * argv[] = { "MyVirtualMainApplication.exe", NULL };
static QCoreApplication *coreApp = nullptr;
static ToolThread *toolThread = nullptr;
};
//! The ToolThread class differs from a standard QThread only
//! in its run() method
class ToolThread : public QThread
{
//! Override QThread's run() method so that it calls
//! the QCoreApplication's exec() method rather than
//! the QThread's own
void run() { ToolThreadGlobal::coreApp -> exec(); }
};
class ThreadStarter : public QObject
{
Q_OBJECT
public:
//! Constructor
ThreadStarter()
{
// Set up the tool thread:
if (!ToolThreadGlobal::toolThread)
{
ToolThreadGlobal::toolThread = new ToolThread();
connect(ToolThreadGlobal::toolThread, &ToolThread::started,
this, &ThreadStarter::createApplication, Qt::DirectConnection);
// The thread's 'started' event is emitted after the thread
// is started but before its run() method is invoked. By
// arranging for the createApplication subroutine to be
// called before run(), we ensure that the required
// QCoreApplication object is instantiated *within the
// thread* before ToolThread's customised run() method
// calls the application's exec() command.
ToolThreadGlobal::toolThread->start();
}
}
//! Destructor
~ThreadStarter()
{
// Ensure that the thread and the QCoreApplication are cleanly
// shut down:
ToolThreadGlobal::coreApp -> quit();
delete ToolThreadGlobal::coreApp;
ToolThreadGlobal::coreApp = nullptr;
delete ToolThreadGlobal::toolThread;
ToolThreadGlobal::toolThread = nullptr;
}
//! Function to return a pointer to the actual tool thread:
ToolThread* getThread() const { return ToolThreadGlobal::toolThread; }
private:
//! Create the QCoreApplication that will provide the tool
//! thread's event loop
/*! This subroutine is intended to be called from the tool
thread itself as soon as the thread starts up.
*/
void createApplication()
{
// Start the QCoreApplication event loop, so long as no
// other Qt event loop is already running
if (QCoreApplication::instance() == NULL)
{
ToolThreadGlobal::coreApp = new QCoreApplication(ToolThreadGlobal::argc,
ToolThreadGlobal::argv);
}
}
};
要使用這一點,從主要的Java應用程序的線程調用的子程序只需要創建一個ThreadStarter對象 將自動與創建ToolThread在其中運行的QCoreApplication:
itsThreadStarter = new ThreadStarter();
itsToolThread = itsThreadStarter -> getThread();
然後我們就可以實例化一個QObject類以通常的方式,將其移動到線程異步和使用調用它的方法QMetaObject :: invokeMethod中:
itsWorker = new Worker();
itsWorker -> moveToThread(itsToolThread);
QMetaObject::invokeMethod(itsWorker, 「doSomethingInteresting」);
當我們做,我們只是刪除ThreadStarter對象一切都很好地清理。除了令人討厭的消息說
WARNING: QApplication was not created in the main() thread
在啓動時,它似乎滿足我所有的要求。
除...(以及最後,這是我的問題)。
有時 - 並且沒有任何我目前能夠辨別的模式 - 在關機過程中出現錯誤。它通常發生在行
delete ToolThreadGlobal::coreApp;
,但有時在該行
ToolThreadGlobal::coreApp -> exec();
(當然,在線程的run執行()方法並不會返回,直到ToolThreadGlobal :: coreApp後 - > quit();已經完全執行)。
錯誤消息通常是一個簡單的訪問衝突;有時它是一個相當更復雜:
ASSERT failure in QObjectPrivate::deleteChildren(): "isDeletingChildren already set, did this function recurse?", file ..\qtbase\src\corelib\kernel\qobject.cpp, line 1927
我以爲這是因爲,一旦我發出退出()命令將QCoreApplication,我要等待一些時間,它在刪除之前,正確關閉事件循環它 - 就像人們通常在刪除它之前通常調用quit()然後在普通的QThread上等待()。然而,QCoreApplication似乎沒有等效的wait()命令,並且我無法實現QTimer來強制延遲,因爲一旦我使用quit()關閉了事件循環,它就無法工作。因此,我無所適從。我有一個暗示,因爲QCoreApplication是一個QObject,我可以調用它的deleteLater()方法,但我看不到應該從哪裏調用它。
是否有專家瞭解QCoreApplication和QThread的來龍去脈並提出解決方案?或者我設計的方式存在根本性缺陷?
你想實現什麼?停止整個過程或刪除Qt部分?退出()停止整個過程,我不明白爲什麼你會想要做任何*調用後。我將假設quit()後的任何刪除操作都是多餘的。 「正在刪除孩子已經設置」聽起來就像那樣。 – ypnos
我想要的是在Java應用程序的其餘部分繼續運行時停止單獨的Qt線程,同時讓事情處於可以在稍後啓動新的Qt線程的狀態。換句話說,我想要讓ToolThreadGlobal命名空間中的兩個指針再次爲空,而沒有任何錯誤消息一直被拋出。 –