QT 中的信号连接方式与线程

这个是我在做毕业设计,尝试使用C++ Qt的时候写的。年代久远,也不知道从哪里东抄抄西抄抄,写在了WizNote里。现在放在博客上,希望能帮到各位的忙。

信号的连接类型

Qt中的信号连接有几种类型,分别在不同的情况下使用。

Constant Value Description
Qt::AutoConnection 0 默认
自动选择连接模式:
1.当两个对象处于同一线程的时候,就选择Qt::DirectConnection;
2.如果两个对象处于不同的线程,就选择Qt::QueuedConnection;
3.连接类型是在信号emit的时候决定的。
Qt::DirectConnection 1 当signal被emit的时候,立刻执行slot,slot将在发送信号的线程中执行
Qt::QueuedConnection 2 当控制权回到接收者的event loop时执行slot,slot在接收方的线程里执行
Qt::BlockingQueuedConnection 3 行为与Qt::QueuedConnection相同,但是发送信号的线程会一直阻塞到slot返回。
绝不能用在发送方与接收方处于同一线程中的情况,否则会造成死锁
Qt::UniqueConnection 0x80 这个flag可以与上述的任意flag合并。使用了这个flag之后,如果连接已经存在,那么QObject::connect()会失败。

为什么Qt::BlockingQueuedConnection会造成死锁?

要注意的是,在 发送信号一方和接收信号的一方处于同一线程内的情况下才会造成死锁。可以想象一下这种情况下会发生什么事:

  1. 发送方将一个信号放入队列;
  2. 发送方等待信号触发的Slot被执行,所以阻塞了当前的线程;
  3. 这时候接收方想要执行这个Signal的Slot,但是当前的线程被阻塞了;
  4. 发送放等待着Slot被执行;
  5. 接收方想要执行Slot,但是线程被阻塞了;
  6. ……

就这样无穷无尽。这也就是我们在操作系统这门课程中学习到的死锁的产生条件:

  • 禁止搶占:no preemption,资源的请求者无法将资源从它的持有者手中抢夺过来,只能等待该资源被持有者主动释放;
  • 持有和等待:hold and wait,已经持有一部分资源,但是还需要别的资源才能继续执行,若这些资源已经被别的进程持有,就要等待这些资源被释放;
  • 互斥:mutual exclusion,对某一个资源,同一时间只能由一个进程占有,如果有别的进程请求该资源,则必须等待当前持有者使用完毕后主动释放;
  • 循環等待:circular waiting,若进程没有拿到工作所需的所有资源,那么就一直等待,直到满足了开始工作的条件,才开始进行工作。

上面描述的死循环,正是一个标准的死锁。

线程编写的两种范式

使用一个单独的Worker类

首先编写一个Worker类,在类中添加一个doWork槽,再自定义一个resultReady信号。在Controller中创建一个新的线程,使用QObject::moveToThread(QThread *)来把这个对象转交给另一个线程。
在转交结束后,这个对象的事件循环就会重置,通过连接Controller和Worker的信号与槽,就可以在两个线程间交互了。

继承QThread类

继承QThread类,并且重写run函数。在需要启动这个线程的时候,就创建一个这个类的对象并调用start()函数。同样地,也可以定义一些信号和槽,并且连接它们。

两种方式的区别

第一种方式和第二种方式达到的效果是相同的,但是有一些细微的差别。如果使用Worker类,并且转交对象至新的线程,那么在连接信号与槽的时候,因为是跨线程的连接,连接的方式默认会是Qt::QueuedConnection。这种连接方式不会造成阻塞。

如果使用的是第二种方法,那么QThread的子类的对象和启动该线程的对象就处于同一个线程中,它们之间的连接就会变成Qt::DirectConnection。 信号发射时槽函数会立刻被调用,并且运行在发送信号一方的线程中,假设在槽函数中需要做一些耗时的工作,那么GUI会被阻塞。

CC BY-NC-SA 4.0 QT 中的信号连接方式与线程 by James & Alice is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Tagged: Tags

发表评论

电子邮件地址不会被公开。 必填项已用*标注

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

This site uses Akismet to reduce spam. Learn how your comment data is processed.