QThread
1. 继承Qthread
2. 重写run()方法
3. 启动线程:start()
4. 线程结束:发出信号finished()
5. 线程退出:quit() (terminate()是直接结束)
6. 等待:wait();
7. 当前线程ID: QThread::currentThread()
8. 休眠:QThread::msleep(1000);
注意:只有run函数内部的代码才会执行在新线程里面
moveToThread
1. MyClass继承Qobject
calss MyClass : Qobject {
// 线程任务
void task() {
}
};
2. MyClass实例化时不能指定父对象(否则无法moveToThread):MyClass myClass = new MyClass();
3. 创建线程:QThread *t = new QThread();
4. 加入线程:myClass->moveToThread(t);
5. 启动线程:t.start(); // 但没有启动线程处理函数
6. 主线程创建信号:void startSignal();
7. 通过信号槽启动线程任务:connect(this, &mainWidget::startSignal, myClass, &MyClass::task);
8. 主线程启动任务:emit startSignal();
9. myClass通知主线程(myClass发出信号void mySignal(),主线程在mainWidgetSlot函数中处理)
connect(myClass, &MyClass::mySignal, [=](const QString &time){
qDebug() << "connect: " << QThread::currentThread();
QMetaObject::invokeMethod(this, "mainWidgetSlot", Q_ARG(QString, time)); // OK: 一个线程调中用另外一个线程中函数的正确姿势
});
或者
connect(myClass, &MyClass::mySignal, this, &mainWidget::mainWidgetSlot());
启动过程与槽函数运行的线程
1. connect mainWidget的信号startSignal和MyCalss的函数task
2. mainWidget触发信号startSignal,则MyCalss的task运行
3. 因为connect时使用默认连接Qt::AutoConnection,而mainWidget处于主线程,MyCalss处于子线程,所以自动选择了队列连接,则task运行在子线程。
4. 同样的,当MyCalss发出信号,mainWidget接收,则mainWidget的槽函数运行在主线程
5. 使用Qt::DirectConnection:直接连接,槽函数在信号发送者所在的线程中运行
6. 使用Qt::QueuedConnection:队列连接,槽函数在信号接收者所在的线程中运行
QRunnable
1. 继承QRunnable
2. 重写run()方法
3. autoDelete()属性,默认为true,运行结束后自动删除对象
QThreadPool
1. 最大线程数量:maxThreadCount()
2. 释放保留的线程:releaseThread()
3. 全局线程池:QThreadPool::globalInstance()
4. 局部线程池(仅在当前类使用)
5. 加入等待队列(并没有马上运行):start()
Qrunnable *r = new Qrunnable();
QThreadPool::globalInstance()->start(r);