使用QThread和QTcpSocket正确使用QThread和moveToThread

时间:2013-10-08 15:57:17

标签: c++ multithreading qt qthread

通过阅读此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(在构造函数中通过传递线程指针),当我离开应用程序时,这变得非常混乱。

我该怎么办?

3 个答案:

答案 0 :(得分:5)

在调用线程上创建类实例。 QTimer继承QObject。 如果调用Qtexec()上的每个线程都可以有一个事件循环。 所以你想将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之前,您应该在此处创建和设置QTimerRun()个对象。由于CommsHandlerIP在创建这些对象之前在新线程中运行,因此它们也将共享相同的线程关联。

答案 1 :(得分:2)

使用QRunnableQThreadPool

如果我转换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);

答案 2 :(得分:1)

我在搜索Timer行为和movetoThread时偶然发现了这一点。 公认的答案是一个好的解决方法,但实际上并不是问题的根本原因。有一个一般规则,即当您移动对象时,所有子对象也会移动。因此,您只需要确保QTimer成为子代,然后在其构造函数中传递this指针即可。

CommsHandlerIPL::CommsHandlerIP()
: QObject(), m_pTimer(new QTimer(this))        // <=== crucial to make it a "child" object 
{
}