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的类作为局部变量声明

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐