- A+
使用事件循环
开启线程
public:
volatile int i;
void ChannelThread::run()
{
qDebug()<<"run";
QTimer timer;
connect(&timer,SIGNAL(timeout()),this,SLOT(slotTimer()),Qt::DirectConnection);
timer.start(1000);
exec();
return;
}
void ChannelThread::slotTimer()
{
qDebug()<<i<<currentThreadId();
i++;
}
QTimer在线程中定义、关联并启动,因此,整个QTimer依附于子线程,采用直连方式Qt::DirectConnection指的是让slotTimer()在信号发送方所依附的线程中执行,如果选择队列方式,则由于this在主线程中定义将依附于主线程,这样,槽函数也将在主线程中执行。定时器的运行需要依赖于事件循环,因此,子线程中的事件循环未开启,则及时定时器start了,也不会执行槽函数。exec()即开启子线程的事件循环,exec()内部其实就是一个死循环,不断处理接收到的事件。
结束线程
channel->quit();
channel->wait();
delete channel;
调用quit方法结束事件循环,即退出了exec()这个死循环,这样,就可以执行run方法中的return方法了,退出run。调用wait();方法是为了确保子线程退出了,已防止在未完全停止子线程的情况下delete而引发crash。
不使用事件循环
开启线程
void ChannelThread::run()
{
qDebug()<<"run";
int i=0;
while (!isInterruptionRequested()) {
QMutexLocker lock(&m_lock);
qDebug()<<i;
i++;
msleep(1000);
}
return;
}
采用isInterruptionRequested()方法控制线程是否停止,该方法只有qt5才具备;采用锁m_lock来决定线程是否暂停。用一个while循环使子线程一直处于运行状态。
暂停线程
void ChannelThread::stop()
{
m_lock.lock();
}
首先在头文件中定义锁:QMutex m_lock,然后m_lock.lock();语句用于获取锁,不一定会在调用stop方法的时候立即暂停线程,可能是稍后暂停线程,这主要取决于何时调用stop方法的线程取得该锁。取得该锁后,循环的子线程将因为得不到锁而处于暂停状态。
继续线程
void ChannelThread::resume()
{
m_lock.unlock();
}
调用resume()方法的线程释放锁,循环中的子线程将因为获得锁而继续循环运行
结束线程
channel->requestInterruption();
channel->wait();
delete channel;
调用requestInterruption方法去请求停止线程,requestInterruption的实现机制实际上是通过互斥锁+标识变量的方式来实现的,通过维护标示变量来指定线程是否运行,循环的子线程将通过isInterruptionRequested()方法判断是否接收到暂停请求,如果接收到,则退出循环,也就意味着线程结束了。但线程的结束并不是立刻进行的,可能是稍后发生的,如果在线程还未停止前调用了delete方法,会引发crash,所以,在delete之前加一句channel->wait();这句话的意思是等待线程完全停止,然后再去delete。