1 信号
(1) void QThread::finished()
这个信号是在相关线程完成执行之前从相关线程发出的。
当发出此信号时,事件循环已经停止运行。除了延迟删除事件外,线程中不再处理其他事件。
这个信号可以连接到QObject::deleteLater(),以释放该线程中的对象。
注意:
- 如果使用terminate()终止了关联的线程,则不确定从哪个线程发出此信号。
-
(2) void QThread::started()
在开始执行run()函数之前,此信号从相关线程发出。
注意:这是一个私有信号。它可以用于信号连接,但不能由用户发出。
公共槽函数有三个, 分别是 quit,start,terminate2 槽
(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()
(3) bool QThread::isRunning()
(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
def run(self):
if not self.is_end:
return
# 终止态才允许启动
self.is_run, self.is_pause, self.is_end = True, False, False
print("线程开启")
i = 0
while i < 10:
self.mutex.lock()
i += 1
print(i)
self.mutex.unlock()
QThread.msleep(500)
self.is_run, self.is_pause, self.is_end = False, False, True
print("线程结束")
def pause(self):
if not self.is_run:
return
# 运行态才允许暂停
print("线程暂停")
self.mutex.lock()
self.is_run, self.is_pause, self.is_end = False, True, False
def resume(self):
if not self.is_pause:
return
# 暂停态才允许恢复
print("线程恢复")
self.mutex.unlock()
self.is_run, self.is_pause, self.is_end = True, False, False
def end(self):
if self.is_end: # 若已经结束, 则直接返回
return
if not self.is_pause:
self.mutex.lock()
print("线程终止")
self.terminate()
self.wait()
self.is_run, self.is_pause, self.is_end = False, False, True
print("线程被强制结束")
self.mutex.unlock()
if name == ‘main‘: app = QApplication()
mt = MyThread()
w = QWidget()
btn1 = QPushButton("线程开启")
btn2 = QPushButton("线程暂停")
btn3 = QPushButton("线程恢复")
btn4 = QPushButton("线程终止")
btn1.clicked.connect(lambda: mt.start())
btn2.clicked.connect(lambda: mt.pause())
btn3.clicked.connect(lambda: mt.resume())
btn4.clicked.connect(lambda: mt.end())
h_layout = QHBoxLayout()
h_layout.addWidget(btn1)
h_layout.addWidget(btn2)
h_layout.addWidget(btn3)
h_layout.addWidget(btn4)
w.setLayout(h_layout)
w.show()
app.exec_()
<a name="d55fdeaa"></a>
## (2) Worker类+moveToThread法
- 使用事
```python
from PySide2.QtCore import QObject, QThread, QMutex, Signal
from PySide2.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout
import time
class Worker(QObject):
sig_done = Signal()
def __init__(self):
super().__init__()
self.mutex = QMutex()
self.is_run = False
self.is_pause = False
self.is_end = True
def do_work(self):
if not self.is_end:
return
# 终止态才允许启动
self.is_run, self.is_pause, self.is_end = True, False, False
print("线程开启")
i = 0
while i < 10:
self.mutex.lock()
i += 1
print(i)
self.mutex.unlock()
QThread.msleep(500)
self.is_run, self.is_pause, self.is_end = False, False, True
print("线程结束")
def pause(self):
if not self.is_run:
return
# 运行态才允许暂停
print("线程暂停")
self.mutex.lock()
self.is_run, self.is_pause, self.is_end = False, True, False
def resume(self):
if not self.is_pause:
return
# 暂停态才允许恢复
print("线程恢复")
self.mutex.unlock()
self.is_run, self.is_pause, self.is_end = True, False, False
def end(self):
if self.is_end: # 若已经结束, 则直接返回
return
if not self.is_pause:
self.mutex.lock()
print("线程终止")
self.sig_done.emit()
self.is_run, self.is_pause, self.is_end = False, False, True
print("线程被强制结束")
self.mutex.unlock()
if __name__ == '__main__':
app = QApplication()
w = QWidget()
btn1 = QPushButton("线程开启")
btn2 = QPushButton("线程暂停")
btn3 = QPushButton("线程恢复")
btn4 = QPushButton("线程终止")
btn1.clicked.connect(lambda: t.start())
btn2.clicked.connect(lambda: wk.pause())
btn3.clicked.connect(lambda: wk.resume())
btn4.clicked.connect(lambda: wk.end())
h_layout = QHBoxLayout()
h_layout.addWidget(btn1)
h_layout.addWidget(btn2)
h_layout.addWidget(btn3)
h_layout.addWidget(btn4)
w.setLayout(h_layout)
w.show()
wk = Worker()
t = QThread()
t.started.connect(wk.do_work)
wk.sig_done.connect(wk.deleteLater)
wk.destroyed.connect(t.quit)
t.finished.connect(t.deleteLater)
wk.moveToThread(t)
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.
结论:
- 并不能成功地强制结束线程
- 运行完后对象均被销毁, 无法重复运行, 只能一次性使用