本程序是基于上一章程序来进行,修改,本章就不介绍,传送门:
线程例子
• lock() : 锁定互斥量 ,如果另外一个线程锁定 了这个互斥量 , 它将阻塞执行直到其他线程f样锁这个互斥量。
• unlock() : 解锁一个互斥量 , 需要与 lock()配对使用 。
• tryLock() : 试图锁定一个互斥量 , 如果成功锁定就返回 true : 如果其他线程已经锁定了这个互斥量,就返回 false , 但不阻塞程序执行。
本文在线程中加入互斥量:
private:
QMutex mutex; //加入互斥量
int m_seq=0;//掷骰子次数序号
int m_diceValue;//骰子点数
bool m_Paused = true; //掷一次骰子
bool m_stop=false; //停止线程
protected:
void run() Q_DECL_OVERRIDE; //线程任务,重载run函数
public:
QDiceThread();
void diceBegin(); //掷一次骰子
void dicePause(); //暂停
void stopThread(); //结束线程
bool readValue(int *seq,int *diceValue); //用于主线程读取数据的函数
添加readValue(int *seq,int *diceValue); //用于主线程读取数据的函数:
bool QDiceThread::readValue(int *seq, int *diceValue)
{
if(mutex.tryLock())
{
*seq = m_seq;
*diceValue = m_diceValue;
mutex.unlock();
return true;
}
else {
return false;
}
}
在run函数中修改成:
void QDiceThread::run()
{
//线程任务
m_stop = false; //启动线程 m_stop=false
m_seq = 0; //掷骰子次数
qsrand(uint(QTime::currentTime().msec())); //随机数初始化,qsrand是线程安全的
while (!m_stop) {
if(!m_Paused)
{
mutex.lock();
m_diceValue = qrand(); //获取随机数
m_diceValue = (m_diceValue % 6) +1;
m_seq++;
mutex.unlock();
// emit newValue(m_seq,m_diceValue); //发送信号
}
msleep(500); //线程休眠500ms
}
// 在 m_stop==true时结束线程任务
quit(); //相当于 exit(0),退出线程的事件循环
}
在 run()函数中 ,对重新计算假子点数和掷假子次数 的 3 行代码用互斥量 mutex 的 lock()和 unlock()进行了保护,这部分代码的执行就不会被其他线程中断。注意 , lock()与 unlock()必须配对使用 。
在 readValue()函数中,用互斥量 mutex 的 tryLock()和 unlock()进行了保护。如果 tryLock()成功锁定互斥量 , 读取数值的两行代码执行时不会被中断,执行完后解锁:如果町Lock()锁定失败,函数就立即返回 ,而不会等待 。
在页面部分采用定时器的方式来获取数据:
private:
int mSeq,mDiceValue;
QDiceThread threadA;
QTimer mTimer;
在槽函数中自定义
private slots:
void onTimeOut(); //定期器处理槽函数
在构造函数中连接槽函数:
connect(&mTimer,SIGNAL(timeout()),this,SLOT(onTimeOut()));
有关函数:
void Dialog::onTimeOut()
{
//定时器处理槽函数
int tmpSeq=0,tmpValue=0;
bool vaild = threadA.readValue(&tmpSeq,&tmpValue); //读取数值
if (vaild && (tmpSeq!=mSeq)) //有效,并且是新数据
{
mSeq=tmpSeq;
mDiceValue=tmpValue;
QString str=QString::asprintf("第 %d 次掷骰子,点数为:%d",mSeq,mDiceValue);
ui->plainTextEdit->appendPlainText(str);
QPixmap pic;
QString filename=QString::asprintf(":/dice/images/d%d.jpg",mDiceValue);
pic.load(filename);
ui->LabPic->setPixmap(pic);
}
}
对应的开始按钮,与结束按钮:
void Dialog::on_btnDiceBegin_clicked()
{
//开始 掷骰子按钮
threadA.diceBegin();
mTimer.start(100);
ui->btnDiceBegin->setEnabled(false);
ui->btnDiceEnd->setEnabled(true);
}
void Dialog::on_btnDiceEnd_clicked()
{
//暂停 掷骰子按钮
threadA.dicePause();
mTimer.stop();
ui->btnDiceBegin->setEnabled(true);
ui->btnDiceEnd->setEnabled(false);
}
这里设置了mTimer.start(100); 100ms的方式来获取数据,低于线程qsleep的时间就可以。
简单的讲解了互斥锁的概念,简单好理解。需要源码的同学可以联系我。