当前位置: 首页 > news >正文

Qt 一次性把多线程实现同步方式说清楚

概念(为何需要同步)

1.多个线程同时读写共享资源(全局/静态内存变量、堆内存动态分配对象、文件/IO/网络句柄、外设资源等),执行顺序不确定,导致数据错乱、崩溃;

2.同步主要是为了保证共享资源互斥访问、线程等待/唤醒、有序执行;

3.测试(没添加同步)

main.cpp

#include <QCoreApplication> #include <QThread> #include <QMutex> #include <QMutexLocker> #include <QReadWriteLock> #include <QReadLocker> #include <QWriteLocker> #include <QWaitCondition> #include <QSemaphore> #include <QAtomicInt> #include <QAtomicPointer> #include <QAtomicInteger> #include <QtConcurrent/QtConcurrent> #include <QDebug> #include <atomic> int g_count_mutex = 0; void mutexTask() { qDebug() << "子线程ID:" << QThread::currentThreadId(); for (int i = 0; i < 10000; ++i) { g_count_mutex++; QThread::msleep(1); } } void demo_QMutex() { g_count_mutex = 0; QFuture<void> t1 = QtConcurrent::run(mutexTask); QFuture<void> t2 = QtConcurrent::run(mutexTask); t1.waitForFinished(); t2.waitForFinished(); qDebug() << "QMutex 最终计数:" << g_count_mutex; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); demo_QMutex(); return 0; //return a.exec(); }

一、方式1

1.QMutex基础互斥锁:

1)保证同一时间仅一个线程进入临界区,保护共享变量读写;

2)API:

--lock(): 加锁,已被占用则阻塞线程,直到释放;

--tryLock(): 非阻塞尝试加锁,获取成功返回true,失败立即返回false;

--tryLock(int timeout): 带超时,超时内拿不到锁返回false;

--unlock(): 释放锁,必须与lock成对调用。

2.测试

main.cpp

//全局共享变量 + 互斥锁 QMutex g_mutex; int g_count_mutex = 0; void mutexTask() { qDebug() << "子线程ID:" << QThread::currentThreadId(); for (int i = 0; i < 10000; ++i) { g_mutex.lock(); g_count_mutex++; g_mutex.unlock(); } } void demo_QMutex() { g_count_mutex = 0; QFuture<void> t1 = QtConcurrent::run(mutexTask); QFuture<void> t2 = QtConcurrent::run(mutexTask); t1.waitForFinished(); t2.waitForFinished(); qDebug() << "QMutex 最终计数:" << g_count_mutex; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); demo_QMutex(); return 0; //return a.exec(); }

二、方式2

1.QMutexLocker(RAII 自动锁):

1)栈对象构造时自动lock,离开作用域(return/异常/花括号结束)自动unlock,无需手动释放;

2.测试

main.cpp

#include <QCoreApplication> #include <QThread> #include <QMutex> #include <QMutexLocker> #include <QReadWriteLock> #include <QReadLocker> #include <QWriteLocker> #include <QWaitCondition> #include <QSemaphore> #include <QAtomicInt> #include <QAtomicPointer> #include <QAtomicInteger> #include <QtConcurrent/QtConcurrent> #include <QDebug> #include <atomic> //全局共享变量 + 互斥锁 QMutex g_mutex; int g_count_mutex = 0; void mutexLockerTask() { qDebug() << "子线程ID:" << QThread::currentThreadId(); for (int i = 0; i < 10000; ++i) { QMutexLocker locker(&g_mutex); //RAII自动加锁/解锁 g_count_mutex++; //QThread::msleep(1); } } void demo_QMutexLocker() { g_count_mutex = 0; QFuture<void> t1 = QtConcurrent::run(mutexLockerTask); QFuture<void> t2 = QtConcurrent::run(mutexLockerTask); t1.waitForFinished(); t2.waitForFinished(); qDebug() << "QMutexLocker 最终计数:" << g_count_mutex; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); demo_QMutexLocker(); return 0; //return a.exec(); }

三、方式3

1.QReadWriteLock读写锁:

1)多个线程可同时获取读锁(读和读不冲突);

2)写锁独占: 有线程持有读锁/写锁时,写线程阻塞;持有写锁时,所有读写线程阻塞;

3)配套RAII工具: QReadLocker、QWriteLocker;

4)API:

--lockForRead(): 获取读锁;

--lockForWrite(): 获取写锁;

--tryLockForRead(int t = 0);

--tryLockForWrite(int t = 0);

--unlock();

2.测试

main.cpp

#include <QCoreApplication> #include <QThread> #include <QMutex> #include <QMutexLocker> #include <QReadWriteLock> #include <QReadLocker> #include <QWriteLocker> #include <QWaitCondition> #include <QSemaphore> #include <QAtomicInt> #include <QAtomicPointer> #include <QAtomicInteger> #include <QtConcurrent/QtConcurrent> #include <QDebug> #include <atomic> QReadWriteLock g_rwLock; int g_data_rw = 0; //读线程 void readTask() { for (int i = 0; i < 100; ++i) { QReadLocker lock(&g_rwLock); //读锁,允许多线程同时读 qDebug() << "读值:" << g_data_rw; QThread::msleep(5); } } //写线程 void writeTask() { for (int i = 0; i < 100; ++i) { QWriteLocker lock(&g_rwLock); //写锁,独占访问 g_data_rw++; qDebug() << "写入值:" << g_data_rw; QThread::msleep(10); } } void demo_QReadWriteLock() { g_data_rw = 0; QFuture<void> r1 = QtConcurrent::run(readTask); QFuture<void> r2 = QtConcurrent::run(readTask); QFuture<void> w1 = QtConcurrent::run(writeTask); r1.waitForFinished(); r2.waitForFinished(); w1.waitForFinished(); qDebug() << "QReadWriteLock 最终值:" << g_data_rw; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); demo_QReadWriteLock(); return 0; //return a.exec(); }

四、方式4

1.QWaitCondition条件变量:

1)线程主动阻塞等待某个条件成立,其他线程修改条件后唤醒等待线程,实现线程间等待/通知,必须配合QMutex使用;

2)API:

--wait(QMutex*, unsigned long timeout): 释放锁,阻塞等待唤醒,超时自动返回;

--wakeOne(): 随机唤醒1个等待线程;

--wakeAll(): 唤醒全部等待线程。

2.测试

main.cpp

#include <QCoreApplication> #include <QThread> #include <QMutex> #include <QMutexLocker> #include <QReadWriteLock> #include <QReadLocker> #include <QWriteLocker> #include <QWaitCondition> #include <QSemaphore> #include <QAtomicInt> #include <QAtomicPointer> #include <QAtomicInteger> #include <QtConcurrent/QtConcurrent> #include <QDebug> #include <atomic> QMutex g_condMutex; QWaitCondition g_cond; int g_buffer = 0; bool g_hasData = false; //消费者 void consumerTask() { QMutexLocker lock(&g_condMutex); // while 循环防止虚假唤醒 while (!g_hasData) { g_cond.wait(&g_condMutex); } qDebug() << "消费数据:" << g_buffer; g_hasData = false; g_cond.wakeOne(); //通知生产者可以继续生产 } //生产者 void producerTask(int val) { QMutexLocker lock(&g_condMutex); while (g_hasData) { g_cond.wait(&g_condMutex); } g_buffer = val; g_hasData = true; qDebug() << "生产数据:" << g_buffer; g_cond.wakeOne(); } void demo_QWaitCondition() { g_hasData = false; QFuture<void> consumer = QtConcurrent::run(consumerTask); QThread::msleep(100); QFuture<void> producer = QtConcurrent::run(producerTask, 999); consumer.waitForFinished(); producer.waitForFinished(); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); demo_QWaitCondition(); return 0; //return a.exec(); }

五、方式5

1.QSemaphore信号量:

1)内置计数器,控制有限资源的并发访问,本质是带计数的条件变量;

2)API:

--acquire(n): 申请n个资源,资源不足则阻塞;

--release(n): 释放n个资源,计数器 + n;

--available(): 返回当前剩余资源数量。

2.测试

main.cpp

#include <QCoreApplication> #include <QThread> #include <QMutex> #include <QMutexLocker> #include <QReadWriteLock> #include <QReadLocker> #include <QWriteLocker> #include <QWaitCondition> #include <QSemaphore> #include <QAtomicInt> #include <QAtomicPointer> #include <QAtomicInteger> #include <QtConcurrent/QtConcurrent> #include <QDebug> #include <atomic> QSemaphore g_sem(2); // 最多允许2个线程同时进入临界区 void semTask(int id) { g_sem.acquire(); // 占用1个资源,超出上限则阻塞 qDebug() << "任务" << id << "进入临界区"; QThread::msleep(1000); qDebug() << "任务" << id << "离开临界区"; g_sem.release(); // 释放资源 } void demo_QSemaphore() { QFuture<void> t1 = QtConcurrent::run(semTask, 1); QFuture<void> t2 = QtConcurrent::run(semTask, 2); QFuture<void> t3 = QtConcurrent::run(semTask, 3); QFuture<void> t4 = QtConcurrent::run(semTask, 4); t1.waitForFinished(); t2.waitForFinished(); t3.waitForFinished(); t4.waitForFinished(); qDebug() << "QSemaphore 全部任务结束"; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); demo_QSemaphore(); return 0; //return a.exec(); }

六、方式6

1.QBasicAtomic/std::atomic原子变量(无锁同步):

1)无锁,CPU 硬件指令保证单个变量原子读写,不需要加锁,性能最高;

2)仅支持基础类型:int、long、指针。

2.测试

main.cpp

#include <QCoreApplication> #include <QThread> #include <QMutex> #include <QMutexLocker> #include <QReadWriteLock> #include <QReadLocker> #include <QWriteLocker> #include <QWaitCondition> #include <QSemaphore> #include <QAtomicInt> #include <QAtomicPointer> #include <QAtomicInteger> #include <QtConcurrent/QtConcurrent> #include <QDebug> #include <atomic> //Qt原子变量 QBasicAtomicInt g_qtAtomic = Q_BASIC_ATOMIC_INITIALIZER(0); //C++标准原子变量 std::atomic<int> g_stdAtomic{0}; void atomicTask() { for (int i = 0; i < 5000; ++i) { g_qtAtomic.ref(); // Qt原子自增 g_stdAtomic.fetch_add(1);// C++原子自增 } } void demo_Atomic() { g_qtAtomic = 0; g_stdAtomic = 0; QFuture<void> t1 = QtConcurrent::run(atomicTask); QFuture<void> t2 = QtConcurrent::run(atomicTask); t1.waitForFinished(); t2.waitForFinished(); qDebug() << "QBasicAtomicInt 计数:" << g_qtAtomic.load(); qDebug() << "std::atomic 计数:" << g_stdAtomic.load(); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); demo_Atomic(); return 0; //return a.exec(); }

七、开发工具及Qt版本

开发工具:Qt Creator 4.10.2

Qt版本:Qt_5_12_6

http://www.jsqmd.com/news/1240477/

相关文章:

  • 金融理财与英语学习:Meta芯片战略与非农数据解析
  • 2026年7月最新帝舵合肥巢湖万达广场维修保养服务电话 - 帝舵中国官方服务中心
  • 手机一贴近耳朵就“黑屏”?原来是?
  • 开源AI私有化部署实战:从零搭建高可用LLM推理平台的7个关键步骤(含K8s+GPU调度秘籍)
  • 苹果手机维修的“信任缺口”:2026年长沙白苹果/无法开机**售后中心深度测评 - 苹果手机电脑维修
  • 计算机毕业设计之学科竞赛管理平台
  • 2026 年 7 月宝玑中国**授权售后网点完整名录|**搬迁、新店启用统一公示公告 - 亨得利腕表服务中心
  • Unity资源热更新实战:基于YooAssets的高效策略与避坑指南
  • PHP生产环境Docker镜像优化实践
  • 【论文解读】复数CVNet:跳过 FFT,Jetson 上 2.75 ms 如何完成雷达手势识别?
  • 智赋岐黄:搭建中医全链条数字化基础设施,助推中医药现代化落地
  • AI模型适用场景匹配度评估:3步精准定位你的业务该用LLM、Diffusion还是传统ML
  • 江阴黄金回收哪里靠谱?本地老牌连锁对比,上门回收更省心 - 行行星
  • Kimi K3订阅:199元年费AI助手在编程与文档处理中的实战指南
  • 雅典**声明:2026年7月泉州最新网点地址及客户售后服务热线 - 亨得利钟表维修中心
  • 线上核验系统焕新教程|2026宝玑全国维修点线上查询渠道升级完整攻略 - 亨得利腕表服务中心
  • DeepMind AGI演进路径:从AlphaGo到Gemini的技术突破与未来展望
  • 三星Galaxy Unpacked将推新折叠屏手机,能否抵御苹果入局冲击?
  • 2025毕业生必看:5大AI降重技术实测对比
  • Google Cloud C++客户端库安装配置全攻略:从依赖管理到项目集成
  • WMSST-CNN融合模型在轴承故障诊断中的应用
  • C++实现俄罗斯方块:从核心算法到图形化实战
  • 亲身到店探访北京美度**售后服务中心|网点地址与售后服务热线(2026年7月最新) - 亨得利官方服务中心
  • LangChain上下文工程:四大策略与实战应用
  • ISTA 3A 运输测试跌落项目 重量对应跌落高度一览
  • 处理小数精度丢失问题
  • 南京建邺亲测靠谱体态店!十年老店矫正真的不套路 - 林州鸿途网络
  • OpenAI 的数学天才在沙盒里学会了越狱:Erdős 猜想模型逃逸事件,比我预期的严重得多
  • Python 元类完全指南:从 type 到 ORM 框架实战
  • 2026 康跃转运|厦门非急救病人护送,长短途接送,持证医护全程监护 - 平台推荐官