Setsuna - Concurrent Programming
type: channel
link: https://kok-s0s.top/index.php/tag/Concurrent-Programming/
items: 造个 C++ 线程基类

造个 C++ 线程基类
type: item
date: 2023-06-10T07:39:00+08:00
description: 写于 2023 年 3 月 24 日。 以剔除 Qt 的 QThread 为目标而诞生的项目。设计的线程基类能搭配类似 Qt 中的信号与槽机制来使用，且利用现代 C++ 提供的互斥量和条件变量，让函数能够同步或异步运行，这样派生类（某业务工作线程）能持有定时器（线程）来做些定时任务（异步）。 cxx_thread 起因 和 记一次「 包轮子 」的经历 的起因一样，只不过这个项目是为了剔除 Qt 的 QThread 而诞生的。 拆分目标 目标 -> 替换掉 QThread 分析下 QThread 这里主要看 QThread 的使用方式，看它如何被使用的。 第一种示例代码 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 &); }; 第一种是在一个继承自 QObject 的子类中，将 QThread 作为成员变量 workerThread，用 moveToThread() 函数将该类所创建的对象移动到 workerThread 中，connect() 函数将信号与槽连接起来，在槽函数中编写需要在线程中处理的逻辑代码。然后再调用 QThread 的 start() 函数来启动 workerThread，这样槽函数就能在一个新的线程中运行。 第二种示例代码 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); workerThread->start(); } 第二种是写子类继承自 QThread，然后重写 run() 函数，这样就可以在 run() 函数中写线程的逻辑。 需要剔除 QThread 的代码中使用方式为第一种。 Signals and Slots Across Threads Qt 有提供一些信号与槽的连接选项 Qt::ConnectionType，这些选项能控制信号与槽的连接方式，比如是否是异步的，是否是阻塞的等等。 简单梳理需求 信号与槽…