首页 > 其他分享 >Qt -- 线程的使用(基础到高级)

Qt -- 线程的使用(基础到高级)

时间:2022-11-14 08:44:23浏览次数:59  
标签:Qt -- void QtConcurrent workerThread 线程 public

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

计算机程序常编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。

今天主要介绍Qt线程四种不同的使用方式,下面结合案例具体说明一下。

一、继承 QThread, 重写 run() 方法,在run()方法中进行费时操作。

这个方法在很多教程上都可以了解到,大家第一个接触的Qt线程操作应该就是它。它的优点是便于理解,缺点是操作繁琐而且需要自己处理线程安全。下面是一个简单的示例。

class WorkerThread : public QThread
{
    Q_OBJECT
    void run() override {
        QString result;
        /* ... here is the expensive or blocking operation ... */
        /**
        while(true)
        {
           qInfo() << "xxxxx";
        }
        */
        emit resultReady(result);
    }
signals:
    void resultReady(const QString&);
};

// ----
void CcObject::startWorkThread()
{
    auto *workerThread = new WorkerThread(this);
    connect(workerThread, &WorkerThread::resultReady, this, &CcObject::handleResults);
    connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
    workerThread->start();
}

另外需要注意如下几点:

  1. 因为workerThread对象创建于旧线程, 所以它的slots函数和调用的方法都将在旧线程中执行。
  2. 非线程安全。
  3. 依赖于Qt的事件循环。

二、使用 QObject的 moveToThread方法。

官方比较推荐的方法。

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork(const QString &parameter) {
        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 *worker = new Worker;
        worker->moveToThread(&workerThread);
        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 &);
};

使用时注意:

  1. 此方法同样依赖于Qt的事件循环。
  2. 同样需要注意线程同步问题。

三、使用 QThreadPool::globalInstance() 线程池操作。

QThreadPool用于管理和回收单个QThread对象,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()进行访问。

以下是一个简单的使用案例:

class Task : public QRunnable
{
    void run() override
    {
        // 费时操作
        qDebug() << "thread run at:" << QThread::currentThread();
    }
};

auto *task = new Task();
QThreadPool::globalInstance()->start(task);

注意事项:

  1. 默认情况下, 用户在调用 QThreadPool::globalInstance()->start(task); 之后不需要再关心task对象的释放问题,因为 QThreadPool 会自动删除 task。当然也可以通过 QRunnable :: setAutoDelete(bool) 调整策略。
  2. 在一定时间内未使用的线程将过期。默认的到期超时为30000毫秒(30秒)。可以使用setExpiryTimeout()进行调整。当设置到期超时为负值时将禁用到期机制。
  3. maxThreadCount()方法可以查询最大线程数,也可以使用setMaxThreadCount()进行调整。默认的maxThreadCount()是QThread::idealThreadCount()。
  4. QThreadPool是一个用于管理线程的低级类,高级玩法请参照 QtConcurrent模块。

四、QtConcurrent模块。(高级玩法)

QtConcurrent模块扩展了Qt Core模块中提供的基本线程支持,并简化了可在所有可用CPU内核上并行执行的代码的开发。
The QtConcurrent namespace provides high-level APIs that make it possible to write multi-threaded programs without using low-level threading primitives such as mutexes, read-write locks, wait conditions, or semaphores. Programs written with QtConcurrent automatically adjust the number of threads used according to the number of processor cores available. This means that applications written today will continue to scale when deployed on multi-core systems in the future.

此模块简化了用户操作,强烈推荐使用。

下面是一个简单的示例。

// 方法参数为 Function 
// 可以处理返回值
QFuture<int> res = QtConcurrent::run([](){ 
    // 费时操作
    return 0;
});

// 可以等待处理完成
// 1.阻塞执行 不阻塞事件循环
// while(!res.isFinished()) {
    // wait
    // QApplication::processEvents(QEventLoop::AllEvents, 200);
// }
// 2. 阻塞等待
res.waitForFinished();

// 处理返回值
int result = res.result();

注意事项:

  1. 需要引入 Qt Concurrent模块。
  2. 可以使用 QFutureWatcher 监视 QFuture。以下是一个官方示例:
// Instantiate the objects and connect to the finished signal.
MyClass myObject;
QFutureWatcher<int> watcher;
connect(&watcher, QFutureWatcher<int>::finished, &myObject, &MyClass::handleFinished);

// Start the computation.
QFuture<int> future = QtConcurrent::run(...);
watcher.setFuture(future);

 

标签:Qt,--,void,QtConcurrent,workerThread,线程,public
From: https://www.cnblogs.com/zzzsj/p/16887934.html

相关文章

  • MongoDB - 入门指南
    组件结构核心进程在MongoDB中,核心进程主要包含了mongod、mongos和mongosh三个。其中最主要的是mongod程序,其在不同的部署方案中(单机部署、副本集部署、分片集群......
  • golang处理时区
    很多Golang初学者都不知道怎么来处理时区问题.这篇文章将解释清楚一下两个问题:怎么把带时区的时间保存到数据库?在Go语言中怎么解析带时区的时间?1.数据库时区(Time......
  • 洛谷 P6142
    先对\(k\)进行二分,将最值问题转化成判定问题。判定一个\(k\)是否合法时,贪心去考虑,一个节点下面的若干条链在合并时,一条链肯定和另一条使它合并后恰好满足长度限制的链......
  • 一个网卡怎么设置多个IP地址
    我们的网卡上面可以可以设置多个IP地址,主要针对软件测试这些,可以增加IP访问等,我们一起看看怎么设置多个IP。1在电脑的右下角联网的图标,右键选择“打开网络和interner设置......
  • 支持JDK19虚拟线程的web框架,之五(终篇):兴风作浪的ThreadLocal
    欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos《支持JDK19虚拟线程的web框架》系列文章链接支持JDK19虚拟线......
  • 《吐血整理》高级系列教程-吃透Fiddler抓包教程(34)-Fiddler如何抓取微信小程序的包-
    1.简介有些小伙伴或者是童鞋们说小程序抓不到包,该怎么办了???其实苹果手机如果按照宏哥前边的抓取APP包的设置方式设置好了,应该可以轻松就抓到包了。那么安卓手机小程序就比......
  • 一年一度!GitHub 开发者大会「GitHub 热点速递 v.22.45」
    GitHub是全球最大的开源社区,它的一举一动都深受每一位开源爱好者的关注。这周末刚落下帷幕的《GitHubUniverse2022》是GitHub发布最新产品、功能、报告和计划的一场......
  • pd.DataFrame函数解析
    1.DataFrame介绍一个Datarame表示一个表格,类似电子表格的数据结构,包含一个经过排序的列表集,它的每一列都可以有不同的类型值(数字,字符串,布尔等等)。Datarame有行和列的索引;它......
  • Linux 安装 Docker
    Docker分为CE和EE两大版本。CE即社区版(免费,支持周期7个月),EE即企业版,强调安全,付费使用,支持周期24个月。DockerCE分为stabletest和nightly三个更新频道。......
  • 【中学】零钱换整钱
    小明手中有硬币,小红手中有若干张10元的纸币。已知1角硬币厚1.8mm,5角硬币厚1.5mm,1元硬币厚2.0mm。小红拿出若干张10元的纸币,小明要将1角的硬币放成一摞,将5角......