Using QThread and moveToThread properly with QTimer and QTcpSocket

前端 未结 3 1693
星月不相逢
星月不相逢 2021-01-02 22:52

From reading this blog, this blog and some others, Subclassing QThread is bad practice. So I tried to apply this method.

But my problem is that I have a QTimer and a

相关标签:
3条回答
  • 2021-01-02 23:32

    There is a much simpler method of achieving all this that follows the same algorithm but doesn't involve all the boilerplating needed to create threads and changing thread affinities, using QRunnable and QThreadPool

    If I convert Merlin069's example, you'll see how it simplifies the code a bit:

    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);
    
    0 讨论(0)
  • 2021-01-02 23:39

    Class Instances are created on the calling thread. QTimer inherits QObject. Each Thread on Qt can have an event loop if it calls exec(). so you want to move QTimer to an event loop on another thread. so you should manually move it.

    Therefore, delay their creation until after you move the object: -

    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();
    

    When the thread is started, the CommsHanderIP Initialise function is called; this is where you should create and setup the QTcpSocket and QTimer objects before calling Run(). As the CommsHandlerIP is running in the new thread before creating those objects, they will also share the same thread affinity.

    0 讨论(0)
  • 2021-01-02 23:52

    I stumbled across this when searching on Timer behaviour and movetoThread. The accepted answer is a good work-around but not really the root cause of the problem. There is a general rule that when you move an object then all child objects will move as well. So you just need to make sure that the QTimer becomes a child so pass the this pointer in its constructor.

    CommsHandlerIPL::CommsHandlerIP()
    : QObject(), m_pTimer(new QTimer(this))        // <=== crucial to make it a "child" object 
    {
    }
    
    0 讨论(0)
提交回复
热议问题