写法1
//.h
class TimeConsuming : public QObject {
Q_OBJECT
public:
explicit TimeConsuming(QObject* parent = nullptr);
void working();
};
//在主线程的使用
auto* thread = new QThread;
auto* work = new TimeConsuming;
work->moveToThread(thread);
QObject::connect(thread, &QThread::started, work, &TimeConsuming::working);
QObject::connect(thread, &QThread::finished, work, &TimeConsuming::deleteLater);
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
个人在耗时但一次的操作中使用较多
写法2
//.h
class Thread : public QThread {
Q_OBJECT
public:
explicit Thread(QObject* parent = nullptr);
~Thread();
void launch(bool b); //启动/关闭
protected:
void run() override;
private:
QMutex m_mutex;
bool m_isRuning = false;//退出循环的条件
}
//.cpp
Thread::Thread(QObject* parent)
: QThread { parent }
{}
Thread::~Thread()
{
launch(false);
if (isRunning())
wait();
}
void Thread::run()
{
for (;;) {
QThread::msleep(1);
...
if (!m_isRuning)
break;
}
}
//见解释1
void Thread::launch(bool b)
{
QMutexLocker locker(&m_mutex);
m_isRuning = b;
if (m_isRuning)
start();
}
//主线程中的使用
auto* thread=new Thread;
thread->launch(true);//启动
thread->launch(false);//关闭
解释1:如果未对退出循环变量m_isRuning上锁,多个线程时,线程被系统调度是不确定的,主线程调用关闭后又接着释放线程,由于子线程的循环里的退出标志还未修改,然后主线程进行了释放,则导致线程在死循环无法退出,Qt会提示“qthread destroyed while thread is still running”。
使用了单例模式,再加上又通讯操作,就很容易出现线程被销毁,但依然被执行的问题。
QMutex
QMutex 是强制互斥的基本类。线程锁定互斥锁,以便获得对共享资源的访问权限。如果第二个线程在互斥锁已锁定的情况下尝试锁定该互斥锁,则第二个线程将处于休眠状态,直到第一个线程完成其任务并解锁互斥锁。
QReadWriteLock
QReadWriteLock 类似于 QMutex,不同之处在于它区分了“读取”和“写入”访问。当一段数据没有被写入时,多个线程同时从中读取是安全的。QMutex 强制多个读取器轮流读取共享数据,但 QReadWriteLock 允许同时读取,从而提高并行度。
QMutex与QMutexLocker的关系
QMutexLocker通常创建为局部变量,QMutexLocker在创建时传入一个并未锁定(若是锁定可用relock重新锁定或unlock解锁)的QMutex指针变量,并且会将QMutex变量锁定,在释放时会将QMutex变量解锁。(QMutexLocker创建时将传入的QMutex锁定,释放时将传入的QMutex解锁)
//QMutex的用法
void Thread::run()
{
m_mutex->lock();//互斥锁锁定
//...操作内容
m_mutex->unlock();//互斥锁解锁
}
//QMutexd搭配QMutexLocker的用法
void Thread::run()
{
//创建QMutexLocker的局部变量,并将类中互斥锁指针传入(此处互斥锁被locker锁定)
QMutexLocker locker(m_mutex);
//...操作内容
//当locker作用域结束locker将互斥锁解锁
}