gpt4 book ai didi

multithreading - 由于另一个 QThread,QApplication 线程卡住

转载 作者:行者123 更新时间:2023-12-04 06:49:54 24 4
gpt4 key购买 nike

在我的 Qt 应用程序中,我创建了一个 QThread那应该定期执行一些繁重的计算任务。主 QApplication线程应该维护一个 GUI(不包括在示例中)并执行一些定期更新。两个线程都有自己的计时器来启用定期的 update() 调用。
问题:当工作线程的计算工作量超过某个临界值时,我的主线程停止接收计时器事件。
示例代码如下。当主线程调用 update() 时输出“Main”,工作线程调用“Worker”。如果你运行它,你会看到“Worker”被定期打印,“Main”正好出现两次(一次在开始,一次在大约 5 秒内)。在全功能 GUI 应用程序的情况下,这实际上意味着 GUI 完全卡住。
一些观察。

  • 通过对内部循环设置 100 个限制(而不是 1000 个)来减少工作量将解决问题(两个 update() 方法都会被定期调用)。
  • 将工作线程计时器信号的连接类型设置为 Qt::DirectConnection 将解决该问题。

  • 所以,正如你所看到的,我有一些解决方法,但我很感激任何人向我解释原始代码有什么问题。我希望线程独立执行它们的事件循环。我知道我通过长时间的 update() 操作阻塞了工作线程事件循环,但是为什么它会影响主线程?
    附言是的,我知道 QConcurrent选择。但我只是想了解一下。
    测试.cpp
    #include <windows.h>
    #include <QApplication>

    #include "test.h"

    HANDLE mainThread_ = INVALID_HANDLE_VALUE;
    QApplication *app_ = 0;
    MyObj *obj_ = 0;
    MyThread *thread_ = 0;

    MyObj::MyObj()
    : timer_(0)
    {
    timer_ = new QTimer(0);
    connect(timer_, SIGNAL(timeout()), this, SLOT(update()));
    timer_->start(10);
    }

    void MyObj::update()
    {
    printf("Main\n");
    }

    void MyThread::run()
    {
    timer_ = new QTimer(0);
    connect(timer_, SIGNAL(timeout()), this, SLOT(update()));
    timer_->start(10);

    exec();
    }

    void MyThread::update()
    {
    printf("Worker\n");

    // do some hard work
    float f = 0.f;
    for (int i=0; i < 100000; ++i)
    {
    for (int j=0; j < 1000; ++j)
    {
    f += i * j;
    }
    }
    }

    int main()
    {
    int argc = 0;
    app_ = new QApplication(argc, 0);

    obj_ = new MyObj();
    thread_ = new MyThread();
    thread_->start();

    QApplication::exec();

    return 0;
    }
    测试.h
    #include <QTimer>
    #include <QThread>

    class MyObj : public QObject
    {
    Q_OBJECT

    public:
    MyObj();

    public slots:
    void update();

    private:
    QTimer *timer_;
    };

    class MyThread : public QThread
    {
    Q_OBJECT

    public:
    void run();

    public slots:
    void update();

    private:
    QTimer *timer_;
    };
    更新:我从可敬的成员那里得到了一些答案(请在下面阅读)。现在我想特别说明是什么错误的想法破坏了我的代码。
    正如您所看到的,该计划有两个线程,每个线程定期运行一些 update() 过程。我的错误是认为 update() 只是一些程序,它是一个 插槽 .具有自己的线程关联的特定对象的插槽,这意味着它的主体将在该线程中执行(除非使用 Qt::DirectConnection 调度信号)。现在,似乎我已经用计时器完成了它——它们中的每一个都属于不同的线程——但是用 update() 搞砸了。所以我最终在主线程中执行了两个 update() 过程。显然,在某些时候,事件循环会被计时器事件淹没,并且永远不会完成迭代。
    至于解决方案。如果您已阅读 "You're doing it wrong" (你确实应该)你知道在一个对象中实现你的所有逻辑是相当方便的,该对象不是从 QThread 子类化的,而是单独创建的,并使用 moveToThread() 附加到 QThread。我个人认为从 QThread 继承子类没有任何问题,如果您记住您的对象只控制线程但不属于它。所以它不是你想在那个线程中执行的代码的地方。

    最佳答案

    这里的第一个问题是你是从 QThread 继承的,正如它所说的 here, "you're doing it wrong".
    您遇到的问题源于线程关联(对象在哪个线程上运行)。例如,如果您要从 QThread 继承并在构造函数中创建对象,而不将对象作为父对象,则该对象将在主线程中运行,而不是在新线程中运行。因此,在 MyThread 构造函数中,您将拥有:-

    MyThread::MyThread()
    : timer_(0)
    {
    timer_ = new QTimer(0);
    connect(timer_, SIGNAL(timeout()), this, SLOT(update()));
    timer_->start(10);
    }
    这里的计时器(timer_)将运行在主线程上,而不是新线程上。
    为了避免重复,我之前的一个答案解释了 thread affinity here .
    解决问题的最佳方法是将您的类更改为从 QObject 继承,然后将该对象移动到新线程。

    关于multithreading - 由于另一个 QThread,QApplication 线程卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19518581/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com