QT的Qthread机制

Helloorld_11 2023-08-03 10:50:47
加精

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

...全文
274 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
鱼弦 2023-08-03
  • 打赏
  • 举报
回复

img

125

社区成员

发帖
与我相关
我的任务
社区描述
全栈技术社区,指在创建一个和谐的技术群体,共同学习进步
qt前端tcp/ip 个人社区 四川省·成都市
社区管理员
  • 鱼弦
  • M malloc
  • 恰柠
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧