赞
踩
目录
QThread要想创建线程,就需要创建出这样类的实例,创建线程的时候,需要重点指定线程的入口函数,创建一个QThread的子类,重写其中的run函数,起到指定入口函数的方式。
run()
|
线程的⼊⼝函数..
|
start()
|
通过调⽤ run() 开始执⾏线程。操作系统将根据优先级参数调度线程。如果线程已经在运⾏,这个函数什么也不做。
|
currentThread()
|
返回⼀个指向管理当前执⾏线程的 QThread的指针。
|
isRunning()
|
如果线程正在运⾏则返回true;否则返回false。
|
sleep() / msleep() / usleep()
|
使线程休眠,单位为秒 / 毫秒 / 微秒
|
wait()
|
阻塞线程,直到满⾜以下任何⼀个条件:
与此 QThread 对象关联的线程已经完成执⾏(即当它从run()返回时)。如果线程已经完成,这个函数将返回 true。如果线程尚未启动,它也返回 true。
已经过了⼏毫秒。如果时间是 ULONG_MAX(默认值),那么等待永远不会超时(线程必须从run()返回)。如果等待超时,此函数将返回 false。这提供了与 POSIX pthread_join() 函数类似的功能
|
terminate()
|
终⽌线程的执⾏。线程可以⽴即终⽌,也可以不⽴即终⽌,这取决于操作系统的调度策略。在terminate() 之后使⽤ QThread::wait() 来确保。
|
finished()
|
当线程结束时会发出该信号,可以通过该信号来实现线程的清理⼯作。
|
由于存在线程安全的问题,多个线程同时对于界面的状态进行修改,此时就会导致界面出错了,因此在qt中,多线程内部不允许对界面的控件状态进行修改,只能在主线程中进行修改。
thread.h
- #ifndef THREAD_H
- #define THREAD_H
- #include <QThread>
- #include <QWidget>
-
- class Thread : public QThread
- {
- Q_OBJECT
- public:
- Thread();
- void run();
- signals:
- void notify();
- };
-
- #endif // THREAD_H
thread.cpp
- #include "thread.h"
-
- Thread::Thread()
- {
-
- }
-
- void Thread::run()
- {
- for(int i = 0 ; i < 10; i++)
- {
- sleep(1);
- emit notify();
- }
- }
widget.h
- #ifndef WIDGET_H
- #define WIDGET_H
- #include "thread.h"
- #include <QWidget>
-
- QT_BEGIN_NAMESPACE
- namespace Ui { class Widget; }
- QT_END_NAMESPACE
-
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- Widget(QWidget *parent = nullptr);
- ~Widget();
- void handle();
- private:
- Ui::Widget *ui;
- Thread thread;
- };
- #endif // WIDGET_H
widget.cpp
- #include "widget.h"
- #include "ui_widget.h"
-
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
-
- connect(&thread,&Thread::notify,this,&Widget::handle);
-
- thread.start();
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
-
- void Widget::handle()
- {
- int value = ui->lcdNumber->intValue();
- ui->lcdNumber->display(--value);
- }
-
客户端中的多线程,主要用于通过多线程的方式,执行一些耗时的等待IO的操作,避免主线程被卡死,比如当用户需要上传/下载一个很大的文件,我们可以使用单独的线程,来处理这种密集的IO操作,要挂起也是挂起这个新的线程,主线程负责事件循环,负责处理用户的各种操作。
- 互斥锁:QMutex、QMutexLocker
- 条件变量:QWaitCondition
- 信号量:QSemaphore
- 读写锁:QReadLocker、QWriteLocker、QReadWriteLock
互斥锁是⼀种保护和防⽌多个线程同时访问同⼀对象实例的⽅法,在 Qt 中,互斥锁主要是通过 QMutex类来处理。QMutex中lock加锁,unlock解锁。
thread.h
- #ifndef THREAD_H
- #define THREAD_H
- #include <QThread>
- #include <QWidget>
- #include <QMutex>
- class Thread : public QThread
- {
- Q_OBJECT
- public:
- Thread();
- void run();
- //共享资源
- static int num;
- //创建一把锁
- QMutex mutex;
- signals:
- void notify();
- };
-
- #endif // THREAD_H
thread.cpp
- #include "thread.h"
-
- int Thread::num=0;
- Thread::Thread()
- {
-
- }
-
- void Thread::run()
- {
- for(int i = 0 ; i < 10; i++)
- {
- mutex.lock();
- num++;
- mutex.unlock();
- }
- }
- #include "widget.h"
- #include "ui_widget.h"
- #include <QDebug>
-
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
- Thread::num=0;
- Thread t1,t2;
- t1.start();
- t2.start();
-
- //让主线程等待两个线程执行完毕
- t1.wait();
- t2.wait();
-
- qDebug()<<Thread::num;
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
上述的代码中,在获取到锁后,执行我们指定的逻辑,一旦发生错误,或者异常将会导致锁未释放,因此我们需要引入 QMutexLocker locker(&mutex);
特点:QMutexLocker 是 QMutex 的辅助类,使⽤ RAII(Resource Acquisition Is Initialization)⽅式 对互斥锁进⾏上锁和解锁操作。⽤途:简化对互斥锁的上锁和解锁操作,避免忘记解锁导致的死锁等问题。
代码示例:
- void Thread::run()
- {
- for(int i = 0 ; i < 10; i++)
- {
- QMutexLocker locker(&mutex); //在作⽤域内⾃动上锁
- num++;
- }//在作⽤域结束时⾃动解锁
- }
此外还有QReadWriteLocker、QReadLocker、QWriteLocker
特点:
- QReadWriteLock 是读写锁类,⽤于控制读和写的并发访问。
- QReadLocker ⽤于读操作上锁,允许多个线程同时读取共享资源。
- QWriteLocker ⽤于写操作上锁,只允许⼀个线程写⼊共享资源。
- ⽤途:在某些情况下,多个线程可以同时读取共享数据,但只有⼀个线程能够进⾏写操作。读写锁提 供了更⾼效的并发访问⽅式。
也就是说多个线程之间的调度是无序的,为了能够一定程度的干预线程之间的执行顺序,需要引入条件变量。
QMutex mutex;QWaitCondition condition;// 在等待线程中mutex. lock ();// 检查条件是否满⾜,若不满⾜则等待while (! conditionFullfilled ()){condition. wait (&mutex); // 等待条件满⾜并释放锁}// 条件满⾜后继续执⾏//...mutex. unlock ();// 在改变条件的线程中mutex. lock ();// 改变条件changeCondition ();condition. wakeAll (); // 唤醒等待的线程mutex. unlock ();
QSemaphore semaphore ( 2 ); // 同时允许两个线程访问共享资源// 在需要访问共享资源的线程中semaphore. acquire (); // 尝试获取信号量,若已满则阻塞// 访问共享资源//...semaphore. release (); // 释放信号量// 在另⼀个线程中进⾏类似操作
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。