Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 与QTimer和QTcpSocket一起正确使用QThread和moveToThread_C++_Multithreading_Qt_Qthread - Fatal编程技术网

C++ 与QTimer和QTcpSocket一起正确使用QThread和moveToThread

C++ 与QTimer和QTcpSocket一起正确使用QThread和moveToThread,c++,multithreading,qt,qthread,C++,Multithreading,Qt,Qthread,通过阅读本文和其他一些文章,子类化QThread是一种糟糕的做法。所以我试着用这个方法 但我的问题是,我想转移到另一个线程的类中有一个QTimer和一个qtcsocket。突然间,这并不像所用的例子那么简单( 这里是CommsHandlerIP类,不包括方法 class CommsHandlerIP : public QObject { Q_OBJECT public: CommsHandlerIP(); ~CommsHandlerIP(void); protected:

通过阅读本文和其他一些文章,子类化QThread是一种糟糕的做法。所以我试着用这个方法

但我的问题是,我想转移到另一个线程的类中有一个QTimer和一个qtcsocket。突然间,这并不像所用的例子那么简单(

这里是CommsHandlerIP类,不包括方法

class CommsHandlerIP : public QObject
{
    Q_OBJECT
public:
    CommsHandlerIP();
    ~CommsHandlerIP(void);
protected:
    QTcpSocket m_TCPSocket;
    QTimer m_timer;
}
问题是,即使移动了CommsHandlerIP,QTimer和qtcsocket(在CommsHandlerIP类内)也在主线程中。因此,我无法启动计时器或连接套接字

如果我尝试移动到QTimer和qtcsocket的线程(例如,在构造函数中通过传递线程指针),当我离开应用程序时,这会变得非常混乱


我该怎么办?

类实例是在调用线程上创建的。
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
初始化函数;在调用
Run()之前,您应该在这里创建和设置
qtcsocket
QTimer
对象
。由于在创建这些对象之前,
CommsHandlerIP
正在新线程中运行,因此它们也将共享相同的线程亲缘关系。

有一种更简单的方法来实现这一切,它遵循相同的算法,但不涉及创建线程和更改线程亲缘关系所需的所有样板文件,使用钕

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

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

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

:QObject(),m_pTimer(new QTimer(this))//我觉得自己很愚蠢,我知道问题出在哪里,但我试图以完全错误的方式解决它。当你知道如何解决问题时,这很容易;O)在构造函数中创建它们时,将
this
作为
m_TCPSocket
m_timer
的父对象传递就足够了。这是因为
更改了此对象及其子对象的线程关联性。因此,您不必延迟它们的创建。是的,但是如果在移动信号/插槽之前已经与它们建立了连接,那么问题可能会在以后发生。创建的连接类型取决于调用方和被调用方的线程亲缘关系。@Merlin069 AFAIK,如果类型是
Qt::AutoConnection
,则在调用
moveToThread()
之前是否建立连接并不重要。这是因为
如果信号是从与接收对象不同的线程发出的,则信号将排队,表现为Qt::QueuedConnection。否则,将直接调用插槽,其行为类似于Qt::DirectConnection。连接类型在发出信号时确定
CommsHandlerIPL::CommsHandlerIP()
: QObject(), m_pTimer(new QTimer(this))        // <=== crucial to make it a "child" object 
{
}