1、有趣的问题
如果线程体函数中开启了事件循环, 线程如何正常结束?
QThread::exec()使得线程进入事件循环
- 事件循环结束前,exec()后的语句无法执行
- quit() 和 exit()函数用于结束事件循环
- quit() ↔ exit(0) , exec()的返回值由exit()参数决定
注意
无论事件循环是否开启,信号发送后会直接进入对
象所依附线程的事件队列;然而,只有开启了事件
循环,对应的槽函数才会在线程中被调用。
2、编程实验
结束事件循环 80-1.pro
#include <QtCore/QCoreApplication>
#include <QDebug>
#include <QThread>
#include "TestThread.h"
#include "MyObject.h"
int main(int argc, char *argv[])
{
//同上节课代码
t.start();
t.wait(8 * 1000); //主线程等待t线程执行结束才向下运行,加上参数代表最多等待8s
t.quit();
return a.exec();
}
设计相关的问题
什么时候需要在线程中开启事件循环?
设计原则
事务性操作(间断性IO操作,等) 可以开启线程的事件循环;
每次操作通过发送信号的方式使得槽函数在子线程中执行。
概念小科普-文件缓冲区
-默认情况下,文件操作时会开辟一段内存作为缓冲区
-向文件中写入的数据会先进入缓冲区
-只有当缓冲区满或者遇见换行符才将数据写入磁盘
缓冲区的意义在于,减少磁盘的低级IO操作,提高文件读写效率!
3、编程实验
文件操作示例
FileWriter.h
#ifndef FILEWRITER_H
#define FILEWRITER_H
#include <QObject>
#include <QFile>
#include <QThread>
class FileWriter : public QObject
{
Q_OBJECT
class Worker : public QThread
{
protected:
void run();
};
QFile m_file;
Worker m_worker;
public:
explicit FileWriter(QString file, QObject *parent = 0);
bool open();
void write(QString text);
void close();
~FileWriter();
signals:
void doWrite(QString text);
void doClose();
protected slots:
void writeSlot(QString text);
void closeSlot();
};
#endif // FILEWRITER_H
FileWriter.cpp
#include "FileWriter.h"
#include <QDebug>
void FileWriter::Worker::run()
{
qDebug() << "void FileWriter::Worker::run() - begin: tid = " << currentThreadId();
exec();
qDebug() << "void FileWriter::Worker::run() - end";
}
FileWriter::FileWriter(QString file, QObject *parent) :
QObject(parent), m_file(file)
{
connect(this, SIGNAL(doWrite(QString)), this, SLOT(writeSlot(QString)));
connect(this, SIGNAL(doClose()), this, SLOT(closeSlot()));
moveToThread(&m_worker); //当前类槽函数都在内部线程执行
m_worker.start();
}
bool FileWriter::open()
{
return m_file.open(QIODevice::WriteOnly | QIODevice::Text);
}
void FileWriter::write(QString text)
{
qDebug() << "void FileWriter::write(QString text) tid = " << QThread::currentThreadId();
emit doWrite(text);
}
void FileWriter::close()
{
qDebug() << "void FileWriter::close() tid = " << QThread::currentThreadId();
emit doClose();
}
void FileWriter::writeSlot(QString text)
{
qDebug() << "void FileWriter::writeSlot(QString text) tid = " << QThread::currentThreadId();
m_file.write(text.toAscii());
m_file.flush(); //强制将缓冲区的内容写到磁盘
}
void FileWriter::closeSlot()//关闭文件也是事务性操作
{
qDebug() << "void FileWriter::closeSlot() tid = " << QThread::currentThreadId();
m_file.close();
}
FileWriter::~FileWriter()
{
m_worker.quit();
}
main.cpp
#include <QtCore/QCoreApplication>
#include <QDebug>
#include <QThread>
#include "FileWriter.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "main() tid = " << QThread::currentThreadId();
FileWriter writer("C:/Users/wss/Desktop/test.txt");
if( writer.open() )
{
writer.write("D.T.Software\r\n"); //三次事务性操作,通过开启子线程完成,耗时在子线程上
writer.write("中文测试\r\n");
writer.write("狄泰软件\r\n");
writer.close();
}
return a.exec();
}
Qt线程的使用模式
-无事件循环模式
★ 后台执行长时间的耗时任务
☛ 文件复制,网络数据读取,等
-开启事件循环横式
★ 执行事务性操作
☛ 文件写入,数据库写入,等
4、小结
QThread ::exec()使得线程进入事件循环
quit()等价于exit(0) , 用于结束线程的事件循环并返回
事务性操作可以开启线程的事件循环,将操作分摊到子线程
工程开发中,多数情况不会开启线程的事件循环
线程多用于执行后台任务或者耗时任务