125
社区成员




QT的Qthread的一些机制和用法
QT提供QThread类以进行多任务处理。与多任务处理一样,Qt提供的线程可以做到单个线程做不到的事情。例如,网络应用程序中,可以使用线程处理多种连接器。
QThread继承自QObject类,且提供QMutex类以实现同步。线程和进程共享全局变量,可以使用互斥体对改变后的全局变量值实现同步。因此,必须编辑全局数据时,使用互斥体实现同步,其它进程则不能改变或浏览全局变量值。
Qt中实现多线程有两种方法:一种是派生QThread类对象的方法,即自定义一个类继承自QThread,并重写run()函数,在run()函数中实现线程要执行的任务;另一种是使用QThread对象的方法,即创建一个QThread对象,并将一个继承自QObject的类的对象移动到该线程中,在该类中定义信号和槽函数来实现线程间的通信和任务执行。
Qt中的线程可以设置优先级、退出、等待、终止等操作,也可以通过信号和槽机制来监听线程的开始和结束事件。Qt还提供了一些静态函数来获取当前线程、理想线程数、线程休眠等信息。
Qt还提供了一些其他的类来辅助线程的管理和同步,如QRunnable、QThreadPool、QFuture、QSemaphore、QWaitCondition等。
下面,我们就来演示一哈,如何使用QThread(例子1):
首先,定义一个Worker类,继承自QObject,并声明一个槽函数doWork()和一个信号resultReady()。
然后,在Worker类的构造函数中,使用qDebug()输出当前线程的地址,以便观察线程的变化。
接着,在doWork()槽函数中,使用QThread::sleep()模拟一个耗时操作,并在完成后发射resultReady()信号。
然后,创建一个QThread对象和一个Worker对象,并使用QObject::moveToThread()将Worker对象移动到QThread对象中。
接着,使用QObject::connect()连接QThread对象的started()信号和Worker对象的doWork()槽函数,以及Worker对象的resultReady()信号和QThread对象的quit()槽函数。
最后,使用QThread::start()启动线程,并使用QThread::wait()等待线程结束!
具体的代码实现如下:
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr) : QObject(parent)
{
qDebug() << "Worker created in thread" << QThread::currentThread();
}
public slots:
void doWork()
{
qDebug() << "Worker started in thread" << QThread::currentThread();
QThread::sleep(5); // simulate a heavy task
qDebug() << "Worker finished in thread" << QThread::currentThread();
emit resultReady();
}
signals:
void resultReady();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Main thread" << QThread::currentThread();
QThread *thread = new QThread(); // create a thread object
Worker *worker = new Worker(); // create a worker object
worker->moveToThread(thread); // move the worker to the thread
QObject::connect(thread, &QThread::started, worker, &Worker::doWork); // connect the thread started signal to the worker doWork slot
QObject::connect(worker, &Worker::resultReady, thread, &QThread::quit); // connect the worker resultReady signal to the thread quit slot
QObject::connect(thread, &QThread::finished, worker, &Worker::deleteLater); // connect the thread finished signal to the worker deleteLater slot
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); // connect the thread finished signal to the thread deleteLater slot
thread->start(); // start the thread
thread->wait(); // wait for the thread to finish
qDebug() << "Main thread finished";
return a.exec();
}
运行上面的代码,结果如下:
Main thread QThread(0x7ffedf9a1b80)
Worker created in thread QThread(0x7ffedf9a1b80)
Worker started in thread QThread(0x55c3c8f3c4c0)
Worker finished in thread QThread(0x55c3c8f3c4c0)
Main thread finished
可以看到,Worker对象最初是在主线程中创建的,但是在执行doWork()槽函数时,已经移动到了子线程中。当doWork()槽函数完成后,发射了resultReady()信号,导致子线程退出,并删除了Worker对象和子线程对象。主线程在等待子线程结束后,也正常退出了。这就是一个简单的多线程的例子。希望对你有帮助。😊
总的来说Qthread的实现是:
创建一个QThread对象和一个继承自QObject的类的对象,这个类中定义了要在线程中执行的任务和信号。
使用QObject::moveToThread()将继承自QObject的类的对象移动到QThread对象中,这样就可以在子线程中执行任务了。
使用QObject::connect()连接QThread对象的信号和继承自QObject的类的对象的槽函数,以及继承自QObject的类的对象的信号和QThread对象的槽函数,以实现线程间的通信和控制。
使用QThread::start()启动线程,并使用QThread::wait()等待线程结束。
下面是一个使用QThread的计时器触发的例子(例子2):
首先,定义一个TimerWorker类,继承自QObject,并声明一个槽函数onTimeout()和一个信号timeout()。
然后,在TimerWorker类的构造函数中,创建一个QTimer对象,并将其timeout()信号连接到自身的onTimeout()槽函数和timeout()信号。
接着,在onTimeout()槽函数中,使用qDebug()输出当前线程的地址和当前时间,以便观察计时器的触发情况。
然后,创建一个QThread对象和一个TimerWorker对象,并使用QObject::moveToThread()将TimerWorker对象移动到QThread对象中。
接着,使用QObject::connect()连接QThread对象的started()信号和TimerWorker对象的start()槽函数,以及TimerWorker对象的timeout()信号和主线程的槽函数。
最后,使用QThread::start()启动线程,并使用QThread::wait()等待线程结束。
代码如下:
#include <QCoreApplication>
#include <QThread>
#include <QTimer>
#include <QDebug>
#include <QDateTime>
class TimerWorker : public QObject
{
Q_OBJECT
public:
explicit TimerWorker(QObject *parent = nullptr) : QObject(parent)
{
qDebug() << "TimerWorker created in thread" << QThread::currentThread();
m_timer = new QTimer(this); // create a timer
m_timer->setInterval(1000); // set the interval to 1 second
connect(m_timer, &QTimer::timeout, this, &TimerWorker::onTimeout); // connect the timer timeout signal to the onTimeout slot
connect(m_timer, &QTimer::timeout, this, &TimerWorker::timeout); // connect the timer timeout signal to the timeout signal
}
public slots:
void start()
{
m_timer->start(); // start the timer
}
void onTimeout()
{
qDebug() << "TimerWorker timeout in thread" << QThread::currentThread();
qDebug() << "Current time:" << QDateTime::currentDateTime().toString();
}
signals:
void timeout();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qDebug() << "Main thread" << QThread::currentThread();
QThread *thread = new QThread(); // create a thread object
TimerWorker *worker = new TimerWorker(); // create a worker object
worker->moveToThread(thread); // move the worker to the thread
QObject::connect(thread, &QThread::started, worker, &TimerWorker::start); // connect the thread started signal to the worker start slot
QObject::connect(worker, &TimerWorker::timeout, [](){qDebug() << "Main thread received timeout signal";}); // connect the worker timeout signal to a lambda function in the main thread
QObject::connect(thread, &QThread::finished, worker, &TimerWorker::deleteLater); // connect the thread finished signal to the worker deleteLater slot
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); // connect the thread finished signal to the thread deleteLater slot
thread->start(); // start the thread
thread->wait(5000); // wait for 5 seconds
thread->quit(); // quit the thread
qDebug() << "Main thread finished";
return a.exec();
}
运行结果如下:
Main thread QThread(0x7ffedf9a1b80)
TimerWorker created in thread QThread(0x7ffedf9a1b80)
TimerWorker timeout in thread QThread(0x55c3c8f3c4c0)
Current time: "2022/12/30 10:15:23"
Main thread received timeout signal
TimerWorker timeout in thread QThread(0x55c3c8f3c4c0)
Current time: "2022/12/30 10:15:24"
Main thread received timeout signal
TimerWorker timeout in thread QThread(0x55c3c8f3c4c0)
Current time: "2022/12/30 10:15:25"
Main thread received timeout signal
TimerWorker timeout in thread QThread(0x55c3c8f3c4c0)
Current time: "2022/12/30 10:15:26"
Main thread received timeout signal
TimerWorker timeout in thread QThread(0x55c3c8f3c4c0)
Current time: "2022/12/30 10:15:27"
Main thread received timeout signal
Main thread finished
可以看到,TimerWorker对象最初是在主线程中创建的,但是在执行onTimeout()槽函数时,已经移动到了子线程中。每隔一秒,计时器就会触发一次timeout()信号,导致onTimeout()槽函数和主线程的lambda函数被执行。主线程在等待5秒后,退出了子线程,并删除了TimerWorker对象和子线程对象。这就是一个使用QThread的计时器触发的例子。
这里再举一个用QThread实现一个子线程调用摄像头的程序(例子3)
首先,使用Qt Designer创建一个UI界面,添加一个QLabel控件用来显示摄像头的画面,添加一个QPushButton控件用来启动和停止摄像头,添加一个QComboBox控件用来选择摄像头的索引号。
然后,定义一个MainWindow类,继承自QMainWindow,并使用Ui_MainWindow类来加载UI界面。
然后,在MainWindow类的构造函数中,创建一个QCamera对象,并将其setViewfinder()函数设置为QLabel控件的地址,这样就可以将摄像头的画面显示到QLabel控件上。
接着,在MainWindow类中,定义一个槽函数on_pushButton_clicked(),用来处理QPushButton控件的clicked()信号,根据QPushButton控件的文本判断是启动还是停止摄像头,并改变QPushButton控件的文本。
接着,在MainWindow类中,定义一个槽函数on_comboBox_currentIndexChanged(),用来处理QComboBox控件的currentIndexChanged()信号,根据QComboBox控件的当前索引值来设置QCamera对象的摄像头索引号,并重新启动摄像头。
最后,简单的总结一哈,QThread的用途!
使用QThread类对象来实现多线程的用途很多,比如:
可以在子线程中执行耗时的操作,如文件读写、网络请求、数据处理等,避免阻塞主线程的用户界面。
可以在子线程中创建和使用继承自QObject的类的对象,如QTimer、QTcpSocket、QUdpSocket、QProcess等,利用信号和槽机制来实现异步的事件处理。
可以在子线程中使用QEventLoop类来创建一个事件循环,以便在子线程中处理事件和信号。(Qt的事件循环是一种机制,用来接收和处理来自操作系统或程序框架的各种事件,如用户输入、窗口绘制、计时器触发等。)
可以在子线程中使用QThreadStorage类来为每个线程创建一个独立的存储空间,以存储线程相关的数据。
可以在子线程中使用QFuture、QFutureWatcher、QFutureSynchronizer等类来实现并行计算和异步结果的获取。
这些都是使用QThread类对象来实现多线程的一些常见用途。
————————————————
版权声明:本文为CSDN博主「Helloorld_1」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Helloorld_1/article/details/132077810