Qt多线程与线程池
1.1 线程常用函数://QThread类常用API//构造函数QThread::QThread(QObject *parent = Q_NULLPTR);//判断线程中的任务是不是处理完毕bool QThread::isFinished() const;//判断字线程是不是在执行任务bool QThread::isRunning() const;//Qt中的线程可以设置优先级//获取当前线程的优
1.1 线程常用函数:
//QThread类常用API
//构造函数
QThread::QThread(QObject *parent = Q_NULLPTR);
//判断线程中的任务是否处理完毕
bool QThread::isFinished() const;
//判断子线程是否在执行任务
bool QThread::isRunning() const;
//Qt中的线程可以设置优先级
//获取当前线程的优先级
Priority QThread::Priority() const;
void QThread::setPriority(Priority priority)
优先级:
QThread::IdlePriority //最低优先级
QThread::LowestPriority
QThread::LowPriority
QThread::NormalPriority
QThread::HighPriority
QThread::HightestPriority
QThread::TimeCriticalPriority
QThread::InheritPriority //最高优先级,默认值
//退出线程,停止底层的事件循环
//退出线程的工作函数
void QThread::exit(int returnCode = 0);
//调用线程退出函数之后不会马上退出当前任务,知道任务结束
//等待任务完成,然后退出线程,一般情况会在exit()后调用
bool QThread:: wait(unsigned long time = ULONG_MAX);
1.2 线程信号与槽
//和调用exit()效果一样
//代用这个函数之后,再调用wait()函数
[slot] void QThread::quit();
//启动子线程
[slot] void QThread::star(Priority priority = InheritPriority );
//线程退出,可能是会马上终止线程,一般情况下不使用这个函数
[slot] void QThread::terminate();
//线程中执行的任务完成了,发送该信号
//任务函数中的处理逻辑执行完毕
[signal] void QThread::finished();
//开始工作之前发出这个信号,一般不使用
[signal] void QThread::started();
1.3 静态函数
//返回一个指向管理当前执行线程的QThread的指针
[static] QThread * QThread::currentThread();
//返回可以在系统上运行的理想线程数 == 当前电脑的CPU核心数
[static] int QThread::idealThreadCount();
//线程休眠函数
[static] void QThread::msleep(unsigned long msecs); //单位:毫秒
[static] void QThread::sleep(unsigned long secs); //单位:秒
[static] void QThread::usleep(unsigned long usecs); //单位:微秒
1.4 任务处理函数
//子线程要处理什么任务都写在run()中
[virtual protected] void QThread::run();
多线程实现方法一:
1.需要创建一个线程类的子类,让其继承QT中的线程类 QThread
class MyThread:public QThread
{
........................
}
2.重写父类的run()方法,在该函数内部编写子线程要处理的具体业务逻辑
class MyThread:public QThread
{
........................
protected:
void run();
}
3.在主线程中创建子线程对象,new一个线程对象
MyThread * mythread = new MyThread();
4.启动子线程,调用start()方法
mythread->start();
不在类的外部调用run方法而是通过start()来间接调用run(),父子线程之间的通信可以通过信号与槽的方式运行
多线程实现方法二:
1.需要创建一个线程类的子类,让其继承QT中的类 QObject
class MyThread:public QObject
{
........................
}
2.在这个类中添加一个公共的成员函数,函数体就是我们要子线程执行的业务逻辑
class MyThread:public QObject
{
........................
//函数名自己指定,叫什么都行,参数根据需求添加
void working();
}
3.在主线程中创建一个QThread对象,这就是子线程的对象
QThread *sub = new QThread;
4.在主线程中创建工作的类的对象(千万不要指定给创建的对象指定父对象)
MyThread *mythread = new MyThread(this); //错误
MyThread *mythread = new MyThread(); //正确
5.将MyThread对象移动到创建的子线程对象中,需要调用QObject类提供的moveToThread()
方法
//void QObject::moveToThread(QThread *target);
//如果给work指定了父对象,这个函数调用就失败了
mythread->moveToThread(sub);
6.启动子线程,调用start()
,这个时候线程起到了,但是移动到线程中的对象并没有工作
//让创建的线程对象执行
sub->start();
7.调用MyThread类对象的工作函数working()
。
//通过信号与槽的方式来启动working()函数
connect(this,&MainWindow::starting,
mythread,&MyThread::working);
//starting是主函数中自定义信号
emit staring();
这种方法可以执行多个任务函数,注意不能给对象指定父类,使用比第一个更加灵活
线程回收:
connect(this,&MainWindow::destory,this,[=]()
{
sub->quit();
sub->wait();
sub->deleteLater();
mythread->deleteLater();
});
线程池的使用:
QT中的QThreadPool类管理了一组QThreads,里边还维护了一个任务队列,QThreadPool管理和回收各个QThread对象,以帮助减少使用线程的程序中的线程创建成本,每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问它
,也可以单独创建一个QThreadPool对象使用。
常用API函数:
//获取和设置线程中的最大线程个数
int maxThreadCount() const;
void setMaxThreadCount(int MaxThreadCount);
//给线程池添加任务,任务是一个QRunnable类型对象
//如果线程池中没有空闲的线程了,任务会放到任务队列中,等待线程处理
void QThreadPool::start(QRunnable *runnable,int priority = 0);
//如果线程池中没有空闲的线程了,直接返回值,任务添加失败,任务不会添加到任务队列中
bool QThreadPool::tryStart(QRunnable *runnable);
//线程池中被激活的线程的个数(正在工作的线程个数)
int QThreadPool::activeThreadCount() const;
//尝试性的将某个任务从线程池队列中删除,如果任务已经开始执行就无法删除
bool QThreadPool::tryTake(QRunnable *runnable);
//将线程池中的任务队列里边没有开始处理的所有任务删除,如果已经开始处理了就无法通过该函数删除
void QThreadPool::clear();
//在每个QT应用程序中都有一个全局的线程池对象,通过该函数访问
static QThreadPool *QThreadPool::globalInstance();
1.创建一个类,继承QObject和QRunnable
class MyWork : public QObject , public QRunnable
{
Q_OBJECT
public:
explicit MyWork(QObject *partent = nullptr)
{
//任务完毕和该对象自动销毁
setAutoDelete(true);
}
~MyWork();
void run() override;
}
在上面的示例中该类是一个多重继承的类,如果需要在这个任务中心使用信号与槽的机制,就必须继承QObject这个类。
2.在主函数中创建该实例对象,调用QThreadPool::globalInstance()->start()
执行线程
//注意该实例对象的父对象不能填this
MyWork *mywork = new MyWork();
QThreadPool::globalInstance()->start(mywork);
如果信号与槽不在同一个线程里面,则需要在connect函数中添加对应的宏
Qt::AutoConnection 自动连接:默认的方式。信号发出的线程和糟的对象在一个线程的时候相当于:DirectConnection,如果是在不同线程,则相当于QueuedConnection
Qt::DirectConnection 直接连接:相当于直接调用槽函数,但是当信号发出的线程和槽的对象不再一个线程的时候,则槽函数是在发出的信号中执行的。
Qt::QueuedConnection 队列连接:内部通过postEvent实现的。不是实时调用的,槽函数永远在槽函数对象所在的线程中执行。如果信号参数是引用类型,则会另外复制一份的。线程安全的。
Qt::BlockingQueuedConnection 阻塞连接:此连接方式只能用于信号发出的线程(一般是先好对象的线程) 和槽函数的对象不再一个线程中才能用。通过信号量+postEvent实现的。不是实时调用的,槽函数永远在槽函数对象所在的线程中执行。但是发出信号后,当前线程会阻塞,等待槽函数执行完毕后才继续执行。
Qt::UniqueConnection 防止重复连接。如果当前信号和槽已经连接过了,就不再连接了。
QObject: Cannot create children for a parent that is in a different thread.
问题:
解决方法:
可以看见QProcess是一个线程类,在子线程中不能将该线程类作为全局变量,将QProcess的类作为局部变量声明
更多推荐
所有评论(0)