回顾:
第一章:Qt的概述
第二章:在Ubuntu编写第一个Qt程序
第三章:Qt的字符串和字符编码
第四章:Qt的信号和槽
第五章:Qt容器窗口(父窗口)
第六章:面向对象的Qt编程
第七章:Qt设计师使用(designer)
第八章:Qt创造器的使用(qtcreator)
第九章:资源和图像
第十章:目录与定时器
第十一章:鼠标和键盘事件
第十二章:Qt数据库(sqlite)
QObject::moveToRhread()
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
/* 耗时或阻塞的操作需要放在独立线程去执行 */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
//创建worker对象,它里面的dowork需要放到线程中
Worker *worker = new Worker;
将worker移动到workerThread线程对象中
worker->moveToThread(&workerThread);
//当operate发送时,dowork将会在独立线程中被执行
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
//开启线程
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
class WorkerThread : public QThread
{
Q_OBJECT
void run() override {
QString result;
/* ... here is the expensive or blocking operation ... */
/* 耗时或阻塞的操作需要放在独立线程去执行 */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
//创建线程对象那个
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
//开启线程,子类中重写run函数将在独立线程中被执行
workerThread->start();
}
pthread_create
void start();
void exit();
void quit()[slot];
pthread_join
void wait();
pthread_cancel
void terminate();
注意使用了terminate
函数后,一般要调用wait
函数,等待系统回收资源,否则容易导致资源浪费或者内存泄漏
eg1:
void run(void){
new 内存;
...
被终止:terminate;
...
delete 内存;
...
}
eg2:
void run(void){
...
加锁;
...
访问全局资源;
...
被终止:terminate;
...
解锁;
...
}
setTerminationEnabled
//enabled=true:默认可以被终止,false默认不允许被终止
void QThread::setTerminationEnabled(bool enabled)
eg:
void run(void){
...
...
setTerminationEnabled(false);
正在执行关键操作:动态资源、数据库、加锁解锁...
setTerminationEnabled(true);
...
...
}
Qt::HANDLE currentThreadId()
案例:多线程打印消息
ThreadDialog.h
#ifndef THREADDIALOG_H
#define THREADDIALOG_H
#include
#include "WorkThead.h"
QT_BEGIN_NAMESPACE
namespace Ui { class ThreadDialog; }
QT_END_NAMESPACE
class ThreadDialog : public QDialog
{
Q_OBJECT
public:
ThreadDialog(QWidget *parent = nullptr);
~ThreadDialog();
private slots:
void on_startButton_clicked();
void on_stopButton_clicked();
private:
Ui::ThreadDialog *ui;
WorkThead threadA;
WorkThead threadB;
};
#endif // THREADDIALOG_H
ThreadDialog.cpp
#include "ThreadDialog.h"
#include "ui_ThreadDialog.h"
ThreadDialog::ThreadDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::ThreadDialog)
{
ui->setupUi(this);
}
ThreadDialog::~ThreadDialog()
{
delete ui;
}
void ThreadDialog::on_startButton_clicked()
{
//
threadA.start();
threadB.start();
ui->startButton->setEnabled(false);
ui->stopButton->setEnabled(true);
}
void ThreadDialog::on_stopButton_clicked()
{
threadA.terminate();
threadA.wait();//
threadB.terminate();
threadB.wait();
ui->startButton->setEnabled(true);
ui->stopButton->setEnabled(false);
}
WorkThread.h
#ifndef WORKTHEAD_H
#define WORKTHEAD_H
#include
#include
//1)继承QThread
class WorkThead:public QThread
{
public:
WorkThead();
~WorkThead();
protected:
//2)重写run函数
void run(void);
};
#endif // WORKTHEAD_H
WorkThread.cpp
#include "WorkThead.h"
WorkThead::WorkThead()
{
}
WorkThead::~WorkThead()
{
}
void WorkThead::run(void)
{
unsigned long threadId = (unsigned long)currentThreadId();
while(1){
qDebug("id=%lu", threadId);
msleep(500);
}
}
QMutex mutex;
void run(void){//线程1
mutex.lock();
访问共享资源;
mutex.unlock();
}
void run(void){//线程2
mutex.lock();
访问共享资源;
mutex.unlock();
}
QReadWriteLock lock;
void ReaderThread::run(){
...
lock.lockForRead();
read_file();
lock.unlock();
}
void WriterThread::run(){
...
lock.lockForWrite();
write_file();
lock.unlock();
}
// 初始化信号计数5:表示有5个可用的共享资源
QSemaphore sem(5); // sem.available() == 5
//获取3个共享资源,剩余2个可用的
sem.acquire(3); // sem.available() == 2
//获取2个共享资源,剩余0个可用的
sem.acquire(2); // sem.available() == 0
//释放5个共享资源,剩余5可用的
sem.release(5); // sem.available() == 5
//又分配5个共享资源,剩余10可用的
sem.release(5); // sem.available() == 10
//尝试获取1个,成功返回true
sem.tryAcquire(1); // sem.available() == 9, returns true
//尝试获取250个
sem.tryAcquire(250); // sem.available() == 9, returns false
生产者和消费者:
#include
#include
#include
const int DataSize = 100000;
const int BufferSize = 8192;
char buffer[BufferSize];
QSemaphore freeBytes(BufferSize);
QSemaphore usedBytes;
class Producer : public QThread
{
public:
void run() override
{
for (int i = 0; i < DataSize; ++i) {
freeBytes.acquire();
buffer[i % BufferSize] = "ACGT"[QRandomGenerator::global()->bounded(4)];
usedBytes.release();
}
}
};
class Consumer : public QThread
{
Q_OBJECT
public:
void run() override
{
for (int i = 0; i < DataSize; ++i) {
usedBytes.acquire();
fprintf(stderr, "%c", buffer[i % BufferSize]);
freeBytes.release();
}
fprintf(stderr, "\n");
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Producer producer;
Consumer consumer;
producer.start();
consumer.start();
producer.wait();
consumer.wait();
return 0;
}
const int DataSize = 100000;
const int BufferSize = 8192;
char buffer[BufferSize];
QWaitCondition bufferNotEmpty;
QWaitCondition bufferNotFull;
QMutex mutex;
int numUsedBytes = 0;
class Producer : public QThread
{
public:
Producer(QObject *parent = NULL) : QThread(parent)
{
}
void run() override
{
for (int i = 0; i < DataSize; ++i) {
mutex.lock();
if (numUsedBytes == BufferSize)
bufferNotFull.wait(&mutex);
mutex.unlock();
buffer[i % BufferSize] = "ACGT"[QRandomGenerator::global()->bounded(4)];
mutex.lock();
++numUsedBytes;
bufferNotEmpty.wakeAll();
mutex.unlock();
}
}
};
class Consumer : public QThread
{
Q_OBJECT
public:
Consumer(QObject *parent = NULL) : QThread(parent)
{
}
void run() override
{
for (int i = 0; i < DataSize; ++i) {
mutex.lock();
if (numUsedBytes == 0)
bufferNotEmpty.wait(&mutex);
mutex.unlock();
fprintf(stderr, "%c", buffer[i % BufferSize]);
mutex.lock();
--numUsedBytes;
bufferNotFull.wakeAll();
mutex.unlock();
}
fprintf(stderr, "\n");
}
signals:
void stringConsumed(const QString &text);
};