1 信号

(1) void QThread::finished()

这个信号是在相关线程完成执行之前从相关线程发出的。
当发出此信号时,事件循环已经停止运行。除了延迟删除事件外,线程中不再处理其他事件。
这个信号可以连接到QObject::deleteLater(),以释放该线程中的对象。
注意:

  • 如果使用terminate()终止了关联的线程,则不确定从哪个线程发出此信号。
  • 这是一个私有信号。它可以用于信号连接,但不能由用户发出。

    (2) void QThread::started()

    在开始执行run()函数之前,此信号从相关线程发出。
    注意:这是一个私有信号。它可以用于信号连接,但不能由用户发出。
    公共槽函数有三个, 分别是 quit,start,terminate

    2 槽

    (1) void QThread::quit()

    告诉线程的事件循环退出,返回代码0(成功)。相当于调用QThread::exit(0)。
    quit()是用来退出exec()事件循环的.
    如果线程没有一个事件循环,这个函数什么也不做
    而且我们写的线程一般是不会添加事件循环的, 所以这个函数不常用

    (2) void QThread::start()

    通过调用run()开始执行线程。如果线程已经在运行,这个函数什么也不做。
    操作系统将根据优先级参数调度线程。
    优先级参数的效果取决于操作系统的调度策略。
    特别是,在不支持线程优先级的系统上,优先级将被忽略。

    (3) void QThread::terminate()

    终止线程的执行。线程 (可能会, 也可能不会) 立即终止,这取决于操作系统的调度策略。
    在terminate()之后使用QThread::wait(),以确保正确。
    当线程终止时,所有等待线程结束的线程将被唤醒。
    警告:此函数很危险,不建议使用。线程可以在其代码路径中的任意点终止。
    可以在修改数据时终止线程。线程没有机会清理自己之后,解锁任何持有互斥锁,等等。
    简而言之,只有在绝对必要时才使用此函数。
    可以通过调用QThread::setTerminationEnabled()显式地启用或禁用终止。在禁用终止时调用此函数将导致延迟终止,直到重新启用终止。

    3 主要接口函数

    (1) void QThread::exit(returnCode)

    告诉线程的事件循环使用返回代码退出。
    调用此函数后,线程离开事件循环并从对QEventLoop::exec()的调用返回。
    函数的作用是::exec()返回returnCode。
    按照惯例,返回码为0(默认值)表示成功,任何非零值表示错误。
    注意,与同名的C库函数不同,这个函数确实会停止事件处理,并返回给调用者returnCode。
    在再次调用QThread::exec()之前,这个线程中不会再启动qeventloop。
    如果QThread::exec()中的eventloop不运行,那么下一个对QThread::exec()的调用也会立即返回。

    (2) bool QThread::isFinished()

    如果线程完成,则返回true;否则,返回false。

    (3) bool QThread::isRunning()

    如果线程正在运行,则返回true;否则,返回false。

    (4) bool QThread::wait(time)

    阻塞调用的线程,直到满足以下任一条件

  • 与该QThread对象关联的线程已完成执行(即,当它从run()返回时)。

    • 如果线程完成,此函数将返回true。
    • 如果线程尚未启动,它也会返回true。
  • 时间毫秒已过去

如果时间为ULONG_MAX(默认值),则等待永远不会超时(线程必须从run()返回)。
如果等待超时,此函数将返回false。

4 用法

(1) 继承QThread法(不使用事件循环, 推荐)

  • 创建一个MyThread类, 继承于QThread.
  • 重写run函数 ```python from PySide2.QtCore import QThread, QMutex from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout

class MyThread(QThread): def init(self): super().init() self.mutex = QMutex() self.is_run = False self.is_pause = False self.is_end = True

  1. def run(self):
  2. if not self.is_end:
  3. return
  4. # 终止态才允许启动
  5. self.is_run, self.is_pause, self.is_end = True, False, False
  6. print("线程开启")
  7. i = 0
  8. while i < 10:
  9. self.mutex.lock()
  10. i += 1
  11. print(i)
  12. self.mutex.unlock()
  13. QThread.msleep(500)
  14. self.is_run, self.is_pause, self.is_end = False, False, True
  15. print("线程结束")
  16. def pause(self):
  17. if not self.is_run:
  18. return
  19. # 运行态才允许暂停
  20. print("线程暂停")
  21. self.mutex.lock()
  22. self.is_run, self.is_pause, self.is_end = False, True, False
  23. def resume(self):
  24. if not self.is_pause:
  25. return
  26. # 暂停态才允许恢复
  27. print("线程恢复")
  28. self.mutex.unlock()
  29. self.is_run, self.is_pause, self.is_end = True, False, False
  30. def end(self):
  31. if self.is_end: # 若已经结束, 则直接返回
  32. return
  33. if not self.is_pause:
  34. self.mutex.lock()
  35. print("线程终止")
  36. self.terminate()
  37. self.wait()
  38. self.is_run, self.is_pause, self.is_end = False, False, True
  39. print("线程被强制结束")
  40. self.mutex.unlock()

if name == ‘main‘: app = QApplication()

  1. mt = MyThread()
  2. w = QWidget()
  3. btn1 = QPushButton("线程开启")
  4. btn2 = QPushButton("线程暂停")
  5. btn3 = QPushButton("线程恢复")
  6. btn4 = QPushButton("线程终止")
  7. btn1.clicked.connect(lambda: mt.start())
  8. btn2.clicked.connect(lambda: mt.pause())
  9. btn3.clicked.connect(lambda: mt.resume())
  10. btn4.clicked.connect(lambda: mt.end())
  11. h_layout = QHBoxLayout()
  12. h_layout.addWidget(btn1)
  13. h_layout.addWidget(btn2)
  14. h_layout.addWidget(btn3)
  15. h_layout.addWidget(btn4)
  16. w.setLayout(h_layout)
  17. w.show()
  18. app.exec_()
  1. <a name="d55fdeaa"></a>
  2. ## (2) Worker类+moveToThread法
  3. - 使用事
  4. ```python
  5. from PySide2.QtCore import QObject, QThread, QMutex, Signal
  6. from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout
  7. import time
  8. class Worker(QObject):
  9. sig_done = Signal()
  10. def __init__(self):
  11. super().__init__()
  12. self.mutex = QMutex()
  13. self.is_run = False
  14. self.is_pause = False
  15. self.is_end = True
  16. def do_work(self):
  17. if not self.is_end:
  18. return
  19. # 终止态才允许启动
  20. self.is_run, self.is_pause, self.is_end = True, False, False
  21. print("线程开启")
  22. i = 0
  23. while i < 10:
  24. self.mutex.lock()
  25. i += 1
  26. print(i)
  27. self.mutex.unlock()
  28. QThread.msleep(500)
  29. self.is_run, self.is_pause, self.is_end = False, False, True
  30. print("线程结束")
  31. def pause(self):
  32. if not self.is_run:
  33. return
  34. # 运行态才允许暂停
  35. print("线程暂停")
  36. self.mutex.lock()
  37. self.is_run, self.is_pause, self.is_end = False, True, False
  38. def resume(self):
  39. if not self.is_pause:
  40. return
  41. # 暂停态才允许恢复
  42. print("线程恢复")
  43. self.mutex.unlock()
  44. self.is_run, self.is_pause, self.is_end = True, False, False
  45. def end(self):
  46. if self.is_end: # 若已经结束, 则直接返回
  47. return
  48. if not self.is_pause:
  49. self.mutex.lock()
  50. print("线程终止")
  51. self.sig_done.emit()
  52. self.is_run, self.is_pause, self.is_end = False, False, True
  53. print("线程被强制结束")
  54. self.mutex.unlock()
  55. if __name__ == '__main__':
  56. app = QApplication()
  57. w = QWidget()
  58. btn1 = QPushButton("线程开启")
  59. btn2 = QPushButton("线程暂停")
  60. btn3 = QPushButton("线程恢复")
  61. btn4 = QPushButton("线程终止")
  62. btn1.clicked.connect(lambda: t.start())
  63. btn2.clicked.connect(lambda: wk.pause())
  64. btn3.clicked.connect(lambda: wk.resume())
  65. btn4.clicked.connect(lambda: wk.end())
  66. h_layout = QHBoxLayout()
  67. h_layout.addWidget(btn1)
  68. h_layout.addWidget(btn2)
  69. h_layout.addWidget(btn3)
  70. h_layout.addWidget(btn4)
  71. w.setLayout(h_layout)
  72. w.show()
  73. wk = Worker()
  74. t = QThread()
  75. t.started.connect(wk.do_work)
  76. wk.sig_done.connect(wk.deleteLater)
  77. wk.destroyed.connect(t.quit)
  78. t.finished.connect(t.deleteLater)
  79. wk.moveToThread(t)
  80. app.exec_()

输出结果:

线程开启 1 2

3

4

5

6

线程暂停

线程恢复

7

8

9

线程终止

线程被强制结束

10

线程结束

再次点击 线程开启按钮, 报错如下:

Traceback (most recent call last):

File “E:/PycharmProjects/TEST/main.py”, line 66, in btn1.clicked.connect(lambda: t.start()) RuntimeError: Internal C++ object (PySide2.QtCore.QThread) already deleted.

结论:

  • 并不能成功地强制结束线程
  • 运行完后对象均被销毁, 无法重复运行, 只能一次性使用