07-线程同步的概念
13.2.1 线程同步的概念
在多线程应用程序中,由于多个线程的存在,线程之间可能需要访问同一个变量,或一个线程需要等待另外一个线程完成某个操作后才产生相应的动作。例如,在上一节的实例samp13_1中,工作线程产生随机的骰子点数,主线程读取骰子点数并显示,主线程需要等待工作线程产生一个新的骰子点数后再读取数据。实例samp13_1中使用了信号与槽的机制,在产生新的骰子数之后通过信号通知主线程读取新的数据。
如果不使用信号与槽机制,QDiceThread的run()函数变为如下的代码:
void QDiceThread::run()
{
m_stop=false;//启动线程时令m_stop=false
m_seq=0;
qsrand(QTime::currentTime().msec());//随机数初始化,qsrand是线程安全的
while(!m_stop)//循环主体
{
if (!m_paused)
{
m_diceValue=qrand(); //获取随机数
m_diceValue=(m_diceValue % 6)+1;
m_seq++;
}
msleep(500); //线程休眠
}
}
那么,QDiceThread需要定义公共函数,返回m_diceValue的值,如:
int QDiceThread::diceValue () { return = m_diceValue;}
以便在主线程中调用此函数读取骰子的点数。
由于没有信号与槽的关联(信号与槽的关系类似于硬件的中断与中断处理函数),主线程只能采用不断查询的方式主动查询是否有新数据,并读取它。但是在主线程调用diceValue()读取骰子点数时,工作线程可能正在执行run()函数里修改m_diceValue值的语句,即:
m_diceValue=qrand(); //获取随机数
m_diceValue=(m_diceValue % 6)+1;
m_seq++;
而且这几条语句计算量大,需要执行较长时间。执行这两条语句时不希望被主线程调用的diceValue()函数中断,如果中断,则主线程得到的可能是错误的值。
这种情况下,这样的代码段是希望被保护起来的,在执行过程中不能被其他线程打断,以保证计算结果的完整性,这就是线程同步的概念。
在Qt中,有多个类可以实现线程同步的功能,包括QMutex、QMutexLocker、QReadWriteLock、QReadLocker、QWriteLocker、QWaitCondition和QSemaphore。下面将分别介绍这些类的用法。