代码之家  ›  专栏  ›  技术社区  ›  Rob

使用qt信号/插槽而不是工作线程

  •  2
  • Rob  · 技术社区  · 15 年前

    我正在使用qt并希望编写一个类来执行一些网络类型操作,类似于ftp/http。这个类需要连接到很多机器,一个接一个,但是我需要应用程序ui在这个过程中保持(相对的)响应性,这样用户就可以取消操作,退出应用程序等等。我的第一个想法是使用一个单独的线程来处理网络事务,但是内置的qt ftp/http(和其他)类显然避免使用线程,而是依赖于信号和插槽。所以,我想做一些类似的事情,希望我能做这样的事情:

    class Foo : public QObject
    {
      Q_OBJECT
    public:
      void start();
    
    signals:
      void next();
    
    private slots:
      void nextJob();
    };
    
    void Foo::start()
    {
      ...
      connect(this, SIGNAL(next()), this, SLOT(nextJob()));
      emit next();
    }
    
    void Foo::nextJob()
    {
      // Process next 'chunk'
    
      if (workLeftToDo)
      {
        emit next();
      }
    }
    
    
    void Bar::StartOperation()
    {
       Foo* foo = new Foo;
       foo->start();
    }
    

    但是,在所有操作完成之前,这不起作用,ui将冻结。我希望发出的信号不会立即调用插槽,而是以某种方式被qt排队,从而允许主ui仍然运行。

    那么,我需要做什么才能让这个工作?qt如何通过在单个线程上执行冗长任务的大量内置类来实现这一点?

    2 回复  |  直到 15 年前
        1
  •  4
  •   shoosh    15 年前

    如果在ui线程中执行长度作业,ui将冻结。避免这种情况的一种方法是偶尔打一次电话 QCoreApplication::processEvents() .

    不过,在你决定做之前,你应该非常小心地理解它的作用。调用此函数意味着gui事件可以在操作过程中触发。如果此事件反过来可以创建更多的作业,则您可以在旧作业进行到一半时启动新作业。

    我不会这么快就放弃worker线程方法。它的优点是将工作与gui完全分离,因此您可以确定已经开始的工作将要完成。
    您还应该考虑windows,特别是有时会给gui循环引入非平凡的延迟。如果主机有点忙或处于内存抖动状态,您将发现gui事件可能需要几秒钟才能完成并将控制权返回到处理过程中。

        2
  •  1
  •   drahnr    15 年前

    将qthread与以下run方法一起使用:

    void run(){ exec(); }
    

    这将提供 另一个 执行循环,在这里你可以做你的“艰苦工作”,而不需要冻结用户界面。

    注意:通过添加

    moveToThread(this);
    

    结束 你的qthread派生线程类的构造函数(文档中没有太多关于它的说明)