Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.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
Multithreading QApplication线程因另一个QThread而冻结_Multithreading_Qt_Qthread_Qtcore - Fatal编程技术网

Multithreading QApplication线程因另一个QThread而冻结

Multithreading QApplication线程因另一个QThread而冻结,multithreading,qt,qthread,qtcore,Multithreading,Qt,Qthread,Qtcore,在我的Qt应用程序中,我创建了一个QThread,它应该定期执行一些繁重的计算任务。MainQApplication线程应该维护一个GUI(不包括在示例中),并执行一些定期更新。两个线程都有自己的计时器来启用常规update()调用 问题:当工作线程的计算负载超过某个临界值时,我的主线程停止接收计时器事件 下面是示例代码。当对主线程调用update()时,它输出“Main”,对工作线程则输出“Worker”。如果您运行它,您将看到“Worker”定期打印,“Main”正好出现两次(一次在开头,一

在我的Qt应用程序中,我创建了一个
QThread
,它应该定期执行一些繁重的计算任务。Main
QApplication
线程应该维护一个GUI(不包括在示例中),并执行一些定期更新。两个线程都有自己的计时器来启用常规update()调用

问题:当工作线程的计算负载超过某个临界值时,我的主线程停止接收计时器事件

下面是示例代码。当对主线程调用update()时,它输出“Main”,对工作线程则输出“Worker”。如果您运行它,您将看到“Worker”定期打印,“Main”正好出现两次(一次在开头,一次在大约5秒钟内)。对于功能齐全的GUI应用程序,这实际上意味着完全冻结GUI

一些观察

  • 通过在内部循环上设置100个限制(而不是1000个限制)来减少工作负载可以解决这个问题(这两个update()方法都将定期调用)
  • 将工作线程计时器信号的连接类型设置为Qt::DirectConnection将解决此问题
  • 所以,正如你所看到的,我在这方面有一些变通方法,但我希望有人能向我解释一下原始代码的问题所在。我希望线程独立地执行它们的事件循环。我知道我正在通过一个长update()操作阻塞工作线程事件循环,但为什么它会影响主线程呢

    是的,我知道
    QConcurrent
    备选方案。但我只是想理解

    test.cpp
    #包括
    #包括
    #包括“test.h”
    句柄主线程=无效的句柄值;
    QApplication*app_u2;=0;
    MyObj*obj_j=0;
    MyThread*线程=0;
    MyObj::MyObj()
    :计时器(0)
    {
    计时器=新的QTimer(0);
    连接(计时器、信号(超时())、此、插槽(更新());
    定时器->启动(10);
    }
    void MyObj::update()
    {
    printf(“主\n”);
    }
    void MyThread::run()
    {
    计时器=新的QTimer(0);
    连接(计时器、信号(超时())、此、插槽(更新());
    定时器->启动(10);
    exec();
    }
    void MyThread::update()
    {
    printf(“Worker\n”);
    //做一些艰苦的工作
    浮点数f=0.f;
    对于(int i=0;i<100000;++i)
    {
    对于(int j=0;j<1000;++j)
    {
    f+=i*j;
    }
    }
    }
    int main()
    {
    int argc=0;
    app=新的QApplication(argc,0);
    obj_uj=新的MyObj();
    线程=新的MyThread();
    线程->开始();
    QApplication::exec();
    返回0;
    }
    
    测试h
    #包括
    #包括
    MyObject类:公共QObject
    {
    Q_对象
    公众:
    MyObj();
    公众时段:
    无效更新();
    私人:
    Q定时器*定时器;
    };
    类MyThread:publicqthread
    {
    Q_对象
    公众:
    无效运行();
    公众时段:
    无效更新();
    私人:
    Q定时器*定时器;
    };
    
    UPD:我从尊敬的会员那里得到了一些答案(请阅读下文)。现在我想澄清是什么错误的想法破坏了我的代码

    正如您所见,计划中有两个线程,每个线程定期运行一些update()过程。我的错误是认为update()只是一个过程,它是一个插槽。特定对象的一个插槽,它有自己的线程亲缘关系,这意味着它的主体将在该线程中执行(除非用Qt::DirectConnection发送信号)。现在,我似乎已经用定时器做得很好了——每个定时器都属于不同的线程——但update()却把事情搞砸了。因此,我最终在主线程中执行了两个update()过程。显然,在某个时刻,事件循环被计时器事件淹没,并且永远不会完成迭代

    至于解决办法。如果您已经读过(并且确实应该读过),您就会知道,在一个对象中实现所有逻辑非常方便,该对象不是从QThread子类化的,而是单独创建的,并使用moveToThread()附加到QThread。就我个人而言,如果您记住您的对象只控制线程而不属于它,那么从QThread生成子类并没有什么错。因此,它不是您希望在该线程中执行代码的位置。

    首先

    从你的主页上,我看不到任何东西像
    GUI
    。。。您只需调用
    QApplication::exec()
    ,无论出于何种原因,而不是
    app->exec()
    (?)

    对于线程问题: 您可以创建一个QObject派生类,该类具有插槽
    doUpdate()
    左右。有了它,您可以像这样做:

    TheUpdateObject* obj = new TheUpdateObject;
    obj->moveToThread(thread_);  // thread_ is a QThread object
    thread_->start();
    connect(thread_, SIGNAL(finished()), obj, SLOT(deleteLater()));
    QTimer* tmr = new QTimer(this);
    tmr->setTimeout(10);
    connect(tmr, SIGNAL(timeout()), obj, SLOT(doUpdate()));
    connect(tmr, SIGNAL(timeout()), tmr, SLOT(start()));
    tmr->start();
    
    因此,计时器应该自行重新启动,并且应该在另一个线程中调用
    doUpdate()


    在GUI内部,您不需要检查更新,qt框架应该在需要时重新绘制。

    这里的第一个问题是您继承了QThread,因此它声明

    您遇到的问题源于线程关联(对象运行在哪个线程上)。例如,如果要从QThread继承并在构造函数中创建对象,而不作为对象的子对象,则该对象将在主线程中运行,而不是在新线程中运行。因此,在MyThread构造函数中,您将有:-

    MyThread::MyThread()
        : timer_(0)
    {
        timer_ = new QTimer(0);
        connect(timer_, SIGNAL(timeout()), this, SLOT(update()));
        timer_->start(10);
    }
    
    这里的计时器(timer_)将在主线程上运行,而不是在新线程上运行。 为了避免重复我自己,我先前的一个答案解释道


    解决此问题的最佳方法是将类更改为从QObject继承,然后将该对象移动到新线程。

    谢谢。事实上,我已经读了很多类似“你做错了”这样的帖子,但直到现在我才开始明白。所以MyThread对象驻留在主线程中,发送给它的计时器事件进入主线程的事件循环。酷。现在,我想知道为什么主线程的update()几乎从来没有机会?我的意思是,两个计时器的间隔相等,它们应该是头对头的。您可以在不同的点(例如构造函数、运行函数和更新函数)从MyObject和MyThread打印线程的地址。这会给你带来快乐
    TheUpdateObject* obj = new TheUpdateObject;
    obj->moveToThread(thread_);  // thread_ is a QThread object
    thread_->start();
    connect(thread_, SIGNAL(finished()), obj, SLOT(deleteLater()));
    QTimer* tmr = new QTimer(this);
    tmr->setTimeout(10);
    connect(tmr, SIGNAL(timeout()), obj, SLOT(doUpdate()));
    connect(tmr, SIGNAL(timeout()), tmr, SLOT(start()));
    tmr->start();
    
    MyThread::MyThread()
        : timer_(0)
    {
        timer_ = new QTimer(0);
        connect(timer_, SIGNAL(timeout()), this, SLOT(update()));
        timer_->start(10);
    }