从阅读这个blog,这个blog和其他一些,Subclassing QThread是不好的做法。所以我尝试应用这种方法。
但我的问题是我在类中有一个QTimer和一个QTcpSocket我想转移到另一个线程。突然间,它并不像使用的例子那么容易。 :(
QThread m_commsThread;
m_pICommsHandler = new CommsHandlerIP();
m_pICommsHandler->moveToThread(&m_commsThread);
m_commsThread.start();
这里是CommsHandlerIP类,不包括方法。
class CommsHandlerIP : public QObject
{
Q_OBJECT
public:
CommsHandlerIP();
~CommsHandlerIP(void);
protected:
QTcpSocket m_TCPSocket;
QTimer m_timer;
}
问题是即使你移动CommsHandlerIP,QTimer和QTcpSocket(在CommsHandlerIP类内)也在主线程中。所以我无法启动计时器或连接插座。
如果我尝试moveToThread QTimer和QTcpSocket(在构造函数中通过传递线程指针),当我离开应用程序时,这变得非常混乱。
我该怎么办?
类实例在调用线程上创建。 QTimer
继承了QObject
。 Qt
上的每个线程如果调用exec()
就可以有一个事件循环。所以你想将QTimer
移动到另一个线程上的事件循环。所以你应该手动移动它。
因此,延迟创建直到移动对象后: -
class CommsHandlerIP : public QObject
{
Q_OBJECT
public slots:
void Initialise();
private:
void Run();
// c++ 11, initialising in headers...
QTimer* m_pTimer = NULL;
QTcpSocket* m_pSocket = NULL;
};
void CommsHandlerIP::Initialise()
{
m_pTimer = new QTimer(this);
m_pSocket = new QTcpSocket(this);
Run();
}
QThread m_commsThread;
m_pICommsHandler = new CommsHandlerIP();
// Note Qt 5 connect style
connect(&m_commsThread, &QThread::started, m_pICommsHandler, &CommsHandlerIP::Initialise);
m_pICommsHandler->moveToThread(&m_commsThread);
m_commsThread.start();
线程启动时,调用CommsHanderIP
Initialise函数;这是你应该在调用QTcpSocket
之前创建和设置QTimer
和Run()
对象的地方。由于CommsHandlerIP
在创建这些对象之前在新线程中运行,因此它们也将共享相同的线程关联。
使用QRunnable和QThreadPool有一个更简单的方法来实现所有这些遵循相同的算法,但不涉及创建线程和更改线程亲和力所需的所有boeplading
如果我转换Merlin069的例子,你会看到它如何简化代码:
class CommsHandlerIP : public QObject, public QRunnable
{
Q_OBJECT
public:
void run();
public slots:
//... any slots
signals:
//... any signals
private:
// c++ 11, initialising in headers...
QTimer* m_pTimer = NULL;
QTcpSocket* m_pSocket = NULL;
};
void CommsHandlerIP::run()
{
m_pTimer = new QTimer();
m_pSocket = new QTcpSocket();
//...
delete m_pTimer;
delete m_pSocket;
}
QThreadPool::globalInstance()->start(new CommsHandlerIP);
在搜索Timer行为和movetoThread时,我偶然发现了这一点。接受的答案是一个很好的解决方案,但不是问题的根本原因。有一个通用规则,当您移动一个对象时,所有子对象也将移动。所以你只需要确保QTimer成为一个孩子,所以在它的构造函数中传递this指针。
CommsHandlerIPL::CommsHandlerIP()
: QObject(), m_pTimer(new QTimer(this)) // <=== crucial to make it a "child" object
{
}