一、多线程程序
QThread类提供了管理线程的方法:
一个对象管理一个线程 一般从QThread继承一个自定义类,重载run函数
1、实现程序
(1)创建项目,基于QDialog
(2)添加类,修改基于QThread
class DiceThread : public QThread
{ Q_OBJECTprivate:int m_seq = 0 ; int m_diceValue; bool m_Paused = true ; bool m_stop = false ; public:explicit DiceThread( ) ; void diceBegin( ) ; void dicePause( ) ; void stopThread( ) ; protected:void run( ) Q_DECL_OVERRIDE; signals:void newValued( int seq, int diceValue) ; public slots:
} ;
DiceThread::DiceThread ( )
{ } void DiceThread::diceBegin ( )
{ m_Paused = false ;
} void DiceThread::dicePause ( )
{ m_Paused = true ;
} void DiceThread::stopThread ( )
{ m_stop = true ;
} void DiceThread::run ( )
{ m_stop = false ; m_seq = 0 ; qsrand( QTime::currentTime( ) .second( )) ; while ( ! m_stop) { if( ! m_Paused) { m_diceValue = qrand( ) %6+1; m_seq++; emit newValued( m_seq, m_diceValue) ; } sleep( 1 ) ; } quit( ) ;
}
(3)实现按钮功能
Dialog::Dialog( QWidget *parent) : QDialog( parent) ,ui( new Ui::Dialog)
{ ui-> setupUi( this) ; ui-> btnStartThread-> setEnabled( true) ; ui-> btnStart-> setEnabled( false) ; ui-> btnStop-> setEnabled( false) ; ui-> btnStopThread-> setEnabled( false) ; connect( & threadA, SIGNAL( started( )) ,this, SLOT( on_threadAStarted( )) ) ; connect( & threadA, SIGNAL( finished( )) ,this, SLOT( on_threadAFinished( )) ) ; connect( & threadA, SIGNAL( newValued( int,int)) ,this, SLOT( on_threadAnewValue( int,int)) ) ;
} Dialog::~Dialog ( )
{ delete ui;
} void Dialog::closeEvent( QCloseEvent *event)
{ if( threadA.isRunning( )) { threadA.stopThread( ) ; threadA.wait( ) ; } event-> accept( ) ;
} void Dialog::on_btnStartThread_clicked ( )
{ threadA.start( ) ;
} void Dialog::on_btnStart_clicked ( )
{ threadA.diceBegin( ) ;
} void Dialog::on_btnStop_clicked ( )
{ threadA.dicePause( ) ;
} void Dialog::on_btnStopThread_clicked ( )
{ threadA.stopThread( ) ;
} void Dialog::on_btnClearText_clicked ( )
{ ui-> plainTextEdit-> clear( ) ;
} void Dialog::on_threadAnewValue( int seq, int diceValue)
{ ui-> plainTextEdit-> appendPlainText( QString::asprintf( "第%d次投色子: 点数%d" , seq, diceValue)) ;
} void Dialog::on_threadAStarted ( )
{ ui-> labelStatus-> setText( "Thread状态:started" ) ; ui-> btnStartThread-> setEnabled( false) ; ui-> btnStart-> setEnabled( true) ; ui-> btnStop-> setEnabled( true) ; ui-> btnStopThread-> setEnabled( true) ;
} void Dialog::on_threadAFinished ( )
{ ui-> labelStatus-> setText( "Thread状态:finished" ) ; ui-> btnStartThread-> setEnabled( true) ; ui-> btnStart-> setEnabled( false) ; ui-> btnStop-> setEnabled( false) ; ui-> btnStopThread-> setEnabled( false) ;
}
二、互斥量
QMutex和QMutexLocker是基于互斥量的线程同步类
QMutex定义的实力是互斥量,主要提供了三个函数 lock():锁定互斥量,如果另一个线程锁定了这个互斥量,将阻塞直到另一个解锁 unlock():解锁一个互斥量 trylock():尝试锁定一个互斥量,如果成功返回true,失败(其他线程已经锁定这个互斥量)返回false,不阻塞线程。 QMutexLocker简化了互斥量的处理 构造一个函数接受一个互斥量作为参数,并将其锁定 析构函数解锁该互斥量
1、实现程序
(1)拷贝上一个项目
(2)修改程序为直接读取
void DiceThread::readValue( int *seq, int *diceValue)
{ *seq = m_seq; *diceValue = m_diceValue;
} void DiceThread::run ( )
{ m_stop = false ; m_seq = 0 ; qsrand( QTime::currentTime( ) .second( )) ; while ( ! m_stop) { if( ! m_Paused) { m_diceValue = 50 ; msleep( 50 ) ; m_diceValue = qrand( ) ; msleep( 50 ) ; m_diceValue = m_diceValue%6+1; msleep( 50 ) ; m_seq++;
// emit newValued( m_seq, m_diceValue) ; } sleep( 1 ) ; } quit( ) ;
}
void Dialog::on_TimerOut ( )
{ int seq, diceValue; threadA.readValue( & seq, & diceValue) ; ui-> plainTextEdit-> appendPlainText( QString::asprintf( "第%d次投色子: 点数%d" , seq, diceValue)) ;
}
(3)使用QMutex互斥量
void DiceThread::readValue( int *seq, int *diceValue)
{ mMutex.lock( ) ; *seq = m_seq; *diceValue = m_diceValue; mMutex.unlock( ) ;
} void DiceThread::run ( )
{ m_stop = false ; m_seq = 0 ; qsrand( QTime::currentTime( ) .second( )) ; while ( ! m_stop) { if( ! m_Paused) { mMutex.lock( ) ; m_diceValue = 50 ; msleep( 50 ) ; m_diceValue = qrand( ) ; msleep( 50 ) ; m_diceValue = m_diceValue % 6 + 1 ; msleep( 50 ) ; m_seq++; // emit newValued( m_seq, m_diceValue) ; mMutex.unlock( ) ; } sleep( 1 ) ; } quit( ) ;
}
(4)使用QMutexLocker
void DiceThread::readValue( int *seq, int *diceValue)
{ QMutexLocker locker( & mMutex) ; *seq = m_seq; *diceValue = m_diceValue;
}
(5)使用QMutex.trylock
bool DiceThread::readValue( int *seq, int *diceValue)
{ // QMutexLocker locker( & mMutex) ; if( mMutex.tryLock( )) { *seq = m_seq; *diceValue = m_diceValue; mMutex.unlock( ) ; return true ; } return false ;
}
三、读写锁
QReadWriteLock提供了以下主要函数:
lockForRead():只读方式锁定资源,如果有其他线程以写入方式锁定,这个函数会阻塞 lockForWrite():以写入方式锁定资源,如果本线程或者其他线程以读取或写入锁定资源,则函数阻塞 unlock():解锁 tryLockForRead():是lockForRead非阻塞版本 tryLockForWrite():是lockForWrite非阻塞版本 读写锁同样有QReadLocker和QWriteLocker
四、条件变量QWaitCondition
QWaitCondition用于通知其他线程,如接收数据和处理数据之间通知。提供了一些函数:
wait(QMutex *lockedMutex):进入等待状态,解锁互斥量lockMutex,被唤醒后锁定lockMutex并退出函数 wakeAll():唤醒所有处于等待的线程,线程唤醒的顺序不确定,有操作系统调度策略决定 QakeOne():唤醒一个处于等待状态的线程,唤醒哪个线程不确定,由操作系统调度策略决定
1、实现程序
(1)拷贝上一个项目
(2)使用QWaitCondition设置数据更新
int m_seq = 0 ;
int m_diceValue;
bool m_stop = false ;
QMutex m_Mutex;
QWaitCondition waitCondition; ProducerThread::ProducerThread ( )
{ } void ProducerThread::stopThread ( )
{ m_stop = true ;
} void ProducerThread::run ( )
{ m_stop = false ; m_seq = 0 ; qsrand( QTime::currentTime( ) .second( )) ; while ( ! m_stop) { m_Mutex.lock( ) ; m_diceValue = qrand( ) % 6 + 1 ; m_seq++; m_Mutex.unlock( ) ; waitCondition.wakeOne( ) ; sleep( 1 ) ; } quit( ) ;
} ConsumerThread::ConsumerThread ( )
{ } void ConsumerThread::stopThread ( )
{ m_stop = true ; waitCondition.wakeOne( ) ; // 需要给wait置信号,否则阻塞无法结束
} void ConsumerThread::run ( )
{ m_stop = false ; while ( ! m_stop) { m_Mutex.lock( ) ; waitCondition.wait( & m_Mutex) ; emit newValued( m_seq, m_diceValue) ; m_Mutex.unlock( ) ; msleep( 100 ) ; } quit( ) ;
}
五、信号量
QSemaphore信号量通常用于保护一定数量的相同的资源。QSemaphore是实现信号量功能的类,提供了以下函数:
acquire(int n):尝试获得n个资源,如果不够将阻塞线程,直到n个资源可用 release(int n):释放资源,如果资源已经全部可用,则可扩充资源总数 int available():返回房前信号量的资源个数 bool tryAcquire(int n=1):尝试获取n个资源,不成功是,不阻塞线程
1、实现程序
(1)创建项目,基于QDIalog
(2)创建线程类
(3)使用信号量实现功能
const int bufferSize = 8 ;
int buffer1[ bufferSize] = { 0 } ;
int buffer2[ bufferSize] = { 0 } ;
int curBuf = 1 ; // 当前采集数据使用的缓冲区QSemaphore semEmptyBufs( 2 ) ; // 两个资源
QSemaphore semFullBufs; ThreadDAQ::ThreadDAQ ( )
{ } void ThreadDAQ::stopThread ( )
{ m_stop = true ;
} void ThreadDAQ::run ( )
{ m_stop = false ; int counter = 0 ; while( ! m_stop) { semEmptyBufs.acquire( ) ; for ( int i = 0 ; i < bufferSize; ++i) { if( curBuf == 1 ) { buffer1[ i] = counter; } else { buffer2[ i] = counter; } counter++; msleep( 50 ) ; } if( curBuf == 1 ) { curBuf = 2 ; } else { curBuf = 1 ; } semFullBufs.release( ) ; } exit( ) ;
} ThreadShow::ThreadShow ( )
{ } void ThreadShow::stopThread ( )
{ m_stop = true ;
} void ThreadShow::run ( )
{ m_stop = false ; int seq = 0 ; while( ! m_stop) { semFullBufs.acquire( ) ; int buf[ bufferSize] = { 0 } ; if( curBuf == 1 ) { memcpy( buf, buffer2, sizeof( int) *bufferSize) ; } else { memcpy( buf, buffer1, sizeof( int) *bufferSize) ; } emit newValue( buf, bufferSize, seq++) ; semEmptyBufs.release( ) ; } exit( ) ;
}
Dialog::Dialog( QWidget *parent) : QDialog( parent) ,ui( new Ui::Dialog)
{ ui-> setupUi( this) ; ui-> btnStopThread-> setEnabled( false) ; connect( & threadConsumer, SIGNAL( newValue( int*, int, int)) ,this, SLOT( on_threadNewValue( int*, int, int)) ) ; connect( & threadProducer, SIGNAL( started( )) ,this, SLOT( on_threadProducer_started( )) ) ; connect( & threadProducer, SIGNAL( finished( )) ,this, SLOT( on_threadProducer_finished( )) ) ; connect( & threadConsumer, SIGNAL( started( )) ,this, SLOT( on_threadConsumer_started( )) ) ; connect( & threadConsumer, SIGNAL( finished( )) ,this, SLOT( on_threadConsumer_finished( )) ) ;
} Dialog::~Dialog ( )
{ delete ui;
} void Dialog::on_threadNewValue( int *data, int count, int seq )
{ QString str = QString::asprintf( "第%03d次,内容:" , seq ) ; for ( int var = 0 ; var < count; ++var) { str += QString::asprintf( "%03d ," , data[ var] ) ; } ui-> plainTextEdit-> appendPlainText( str) ;
} void Dialog::on_btnStartThread_clicked ( )
{ threadConsumer.start( ) ; threadProducer.start( ) ; ui-> btnStartThread-> setEnabled( false) ; ui-> btnStopThread-> setEnabled( true) ;
} void Dialog::on_btnStopThread_clicked ( )
{ threadProducer.stopThread( ) ; threadConsumer.stopThread( ) ; ui-> btnStartThread-> setEnabled( true) ; ui-> btnStopThread-> setEnabled( false) ;
} void Dialog::on_btnClearText_clicked ( )
{ ui-> plainTextEdit-> clear( ) ;
} void Dialog::on_threadProducer_started ( )
{ ui-> labelProducer-> setText( "Producer线程:started" ) ;
} void Dialog::on_threadProducer_finished ( )
{ ui-> labelProducer-> setText( "Producer线程:finished" ) ;
} void Dialog::on_threadConsumer_started ( )
{ ui-> labelConsumer-> setText( "Consumer线程:started" ) ;
} void Dialog::on_threadConsumer_finished ( )
{ ui-> labelConsumer-> setText( "Consumer线程:finished" ) ;
}