做英语题的网站seo推广专员工作好做吗

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

做英语题的网站,seo推广专员工作好做吗,wordpress登录不了,宁波品牌策划公司文章目录 前言1. Qt 多线程概述2. QThread 常用 API3. 使用线程4. 多线的使用场景5. 线程安全问题5.1. 加锁5.2. QReadWriteLocker、QReadLocker、QWriteLocker 6. 条件变量 与 信号量6.1. 条件变量6.2 信号量 总结 前言 在现代软件开发中#xff0c;多线程编程已成为一个不可… 文章目录 前言1. Qt 多线程概述2. QThread 常用 API3. 使用线程4. 多线的使用场景5. 线程安全问题5.1. 加锁5.2. QReadWriteLocker、QReadLocker、QWriteLocker 6. 条件变量 与 信号量6.1. 条件变量6.2 信号量 总结 前言 在现代软件开发中多线程编程已成为一个不可或缺的技能尤其是在需要处理复杂任务和提高应用程序性能的场合。Qt作为一个跨平台的应用程序框架提供了强大的多线程支持使得开发者能够充分利用多核处理器的优势开发出响应迅速且高效的应用程序。本文将深入探讨Qt多线程的基本概念、API使用、线程安全问题以及同步机制旨在帮助开发者更好地理解和运用Qt的多线程功能。

  1. Qt 多线程概述 Qt 多线程 和 Linux 中线程本质是一个东西。 Linux 中的各种和线程相关的 原理 和 注意事项都是在Qt中适用的。 Qt 中的多线程 API Linux 中的多线程 APILinux 系统提供的 pthread 库Qt 中针对系统提供的线程 API 重新封装了。 C 11 中也引入了线程 std::thread Linux 原生多线程 API设计的非常差使用起来非常不方便也是 C 语言本身的局限性引起的实际开发中很少使用原生 api std::thread 要比 Linux 的 API 要更好一些 Qt 中的多线程 API还要好一点其实参考了 Java 中的线程库 API 的设计方式。 QThread 要想创建线程就要创建出这样的实例创建线程的时候需要重点指定线程的入口函数。创建一个 QThread 的子类重写其中 run 函数起到指定函数入口的方式多态 C 中这种做法不算特别常见相比之下 std::thread 直接指定回调的方式更常见一些有些 C 的大佬认为多态机制带来运行时的额外开销运行时查询虚函数表找到对应的函数再执行 有些场景确实对于性能追求到极致游戏引擎AI做高性能服务器… Qt 做客户端开发客户端性能只要不太拉跨就行 性能从来不是Qt优先追求的
  2. QThread 常用 API start(): 这个操作就是真正调用系统 API 创建线程新的线程创建出来之后自然就会自动执行 run 函数。 可以使用 wait, 让一个线程等待另一个线程执行结束
  3. 使用线程 实例 之前基于定时器写过倒计时这样的程序。 也可以通过线程来完成类似的功能。定时器内部本质上也是可以基于多线程来实现的。Qt 的定时器是否基于多线程不太清楚 创建另一个线程新线程中进行计时搞一个循环每循环一次sleep 1ssleep完成就可以更新界面了 由于存在线程安全问题多个线程时对于界面的状态进行修改此时就会导致界面就出错了。Qt选择了一刀切针对界面控件状态进行任何修改务必在主线程中执行。 // widget.h #ifndef WIDGET_H #define WIDGET_H#include QWidget #include thread.hQT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget();Thread thread;void handle(); private:Ui::Widget *ui; }; #endif // WIDGET_H// widget.cpp #include widget.h #include ui_widget.hWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui-setupUi(this);// 连接信号槽通过槽函数跟新界面connect(thread, Thread::notify, this, Widget::handle);// 要启动一下线程thread.start(); }Widget::~Widget() {delete ui; }void Widget::handle() {// 此处修改界面内容int value ui-lcdNumber-intValue();value–;ui-lcdNumber-display(value); }// thread.h #ifndef THREAD_H #define THREAD_H#include QWidget #include QThreadclass Thread : public QThread {Q_OBJECT public:Thread();// 要用的目的是重写父类的方法 run 方法void run();signals:void notify(); // 只用声明不用定义 };#endif // THREAD_H// thread.cpp #include thread.hThread::Thread() {}void Thread::run() {// 在这个 run 中。能否直接去进行修改界面内容呢// 不可以// 虽然不可以修改界面但是可以针对时间来进行计时// 当每到一秒钟的时候通过信号槽来通知主线程负责更新界面内容for (int i 0; i 10; i) {// sleep 本身是 QThead 的成员函数 就可以直接调用sleep(1);// 发送一个信号通知主线程emit notify();} }4. 多线的使用场景 之前学习多线程主要还是站在服务器开发的角度来看待的。 当时谈到多线程最主要的目的是为了充分利用多核 CPU 的计算资源。双路 CPU一个主板上有两个CPU。 客户端多线程仍然非常有意义侧重点就不同了对于普通用户来说“使用体验”是一个非常重要的话题。 如果“非常快”的代价是“系统很卡”用户大概率是不会买账的虽然普通用户的家用 PC 上也是多核CPU客户端上的程序很少会使用多线程把 CPU 计算资源吃完。 相比之下客户端的多线程主要是用于通过多线程的方式执行一些耗时的操作避免主线程被卡死避免对用户造成一些不好的体验。 比方说客户端经常会和服务器进行网络通信比方说客户端要上传/下载一个很大的文件传输需要好久20分钟像这样就是算是密集的IO操作比如代码中持续不断的进行 QFile.write这种密集 IO 就会使程序被系统阻塞挂起一旦进程都被挂起了此时意味着用户进行各种操作程序都无响应。比如启动吃鸡启动过程中就需要从文件/网络 加载大量的资源此时如果你狂点鼠标窗口很可能这个窗口就僵住了“WIndows 提示你这个窗口不能响应是否要强制结束” 因此相比之下更好的做法使用单独的线程来处理这种密集 IO 操作要挂起也是挂起这个新的线程。主线程负责用户的各种操作此时主线程仍然可以继续工作继续响应用户的各种操作。
  4. 线程安全问题 多线程程序太复杂了 5.1. 加锁 把多个线程访问的公共资源通过锁保护起来。把并发执行变成串行执行。 Linux: mutex 互斥量。 C11: 引入 std::mutex Qt 同样也提供了对应的锁来针对系统提供的锁进行封装。 QMutex: lock 加锁 unlock 解锁。 void Thread::run() {for (int i 0; i 50000; i) {num;} }#include mainwindow.h #include ui_mainwindow.h#include thread.h #include QDebugMainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui-setupUi(this);// 创建两个线程对象Thread t1;Thread t2;t1.start();t2.start();// 加上线程的等待,让主线程等待这两线程执行结束t1.wait();t2.wait();// 打印结果qDebug() Thread::num; }MainWindow::~MainWindow() {delete ui; }由于三个线程之间是并发执行的关系当 t1 和 t2 运行起来之后主线程仍然会继续往后执行执行到打印的时候大概率 t1、t2 还没执行呢所以要加上wait进行阻塞等待 最后打印出来的结果并不是我们预期中的100,000 说明是存在bug说明是存在线程安全问题 // 创建锁对象 static QMutex mutex; 多个线程加锁的对象得是同一个对象不同对象此时不会产生锁的互斥也就无法把 并发执行 - 串行执行也就无法解决上述问题。 #include thread.hint Thread::num 0; QMutex Thread::mutex;Thread::Thread() {}void Thread::run() {for (int i 0; i 50000; i) {mutex.lock();num;mutex.unlock();} }num; 是一个两个线程访问的公共变量之前如果并发执行就可能第一个线程修改了一半第二个线程也进行了修改就容易出现问题。操作对应 三个cpu指令在操作系统中详细介绍 加了锁之后第一个线程顺利拿到锁继续执行在第一个线程没有执行完的时候第二个线程也尝试枷锁就会阻塞等待。一直等待到第一个线程加锁第二个线程才可能从阻塞中被唤醒。
    for (int i 0; i 50000; i) {mutex.lock();num;mutex.unlock(); }像这里的锁,很容易忘记unlock,实际开发中, 加锁之后涉及到的逻辑可能很复杂下面很容易就忘记释放锁。 比如下面也算是没释放锁 mutex.lock(); if (…) {return; } mutex.unlock();或者抛出异常释放动态内存也会存在类似的问题。 C 引入 智能指针,就是为了解决上述的问题。 C11 引入了 std::lock_guard, 相当于是 std::lock_guard, 相当于是 std::mutex 智能指针, 借助 RAII 机制。 {std::lock_guard guard(mutex);// 执行各种逻辑… } // 大括号执行完毕guard 变量的声明周期结束在析构的时候执行unlock了。上述方案Qt 也参考过来了: QMutexLocker #include thread.h #include QMutexLockerint Thread::num 0; QMutex Thread::mutex;Thread::Thread() {}void Thread::run() {for (int i 0; i 50000; i) {QMutexLocker locker(mutex);// mutex.lock();num;// mutex.unlock();} }Qt 的锁 和 C标准库中的锁本质上都是封装的系统提供的锁编写多线程代码的时候可以使用 Qt 的锁也可以使用 C 的锁。 C 的锁能锁Qt 的线程吗? 是可以的虽然混着用也行但一般不建议 5.2. QReadWriteLocker、QReadLocker、QWriteLocker 特点 QReadWriteLock 是读写锁类用于控制读和写的并发访问。 QReadLocker 用于读操作上锁允许多个线程同时读取共享资源。 QWriteLocker 用于写操作上锁只允许一个线程写入共享资源。 用途在某些情况下多个线程可以同时读取共享数据但只有一个线程能够进行写操作。读写锁提供了更高效的并发访问方式。 QReadWriteLock rwLock; //在读操作中使⽤读锁 {QReadLocker locker(rwLock); //在作⽤域内⾃动上读锁//读取共享资源//…} //在作⽤域结束时⾃动解读锁 //在写操作中使⽤写锁 {QWriteLocker locker(rwLock); //在作⽤域内⾃动上写锁//修改共享资源//…} //在作⽤域结束时⾃动解写锁6. 条件变量 与 信号量 Qt 中的条件变量 与 信号量 和 Linux 中的条件变量、信号量一致。 6.1. 条件变量 多个线程之间调度是无序的为了能够一定程度干预线程之间的顺序引入条件变量。 在 Qt 中专门提供了 QWaitCondition类 来解决像上述这样的问题。 wait中就会先释放锁 等待 要想释放锁前提就是先获取到锁。 QMutex mutex; QWaitCondition condition; //在等待线程中 mutex.lock(); //检查条件是否满⾜若不满⾜则等待 while (!conditionFullfilled()) // {condition.wait(mutex); //等待条件满⾜并释放锁 } //条件满⾜后继续执⾏ //… mutex.unlock(); //在改变条件的线程中 mutex.lock(); //改变条件 changeCondition(); condition.wakeAll(); //唤醒等待的线程 mutex.unlock();判定线程继续执行的条件是否成立不成立就进行wait等待。 这里要使用 while 判定而不是 if因为唤醒之后还需要确认一下当前条件是不是真的成立了。wait 可能被提前唤醒可能被信号打断了 6.2 信号量 有时在多线程编程中需要确保多个线程可以相应的访问⼀个数量有限的相同资源。例如运行程序的设备可能是非常有限的内存因此我们更希望需要大量内存的线程将这⼀事实考虑在内并根据可用的内存数量进行相关操作多线程编程中类似问题通常用信号量来处理。信号量类似于增强的互斥锁不仅能完成上锁和解锁操作而且可以跟踪可用资源的数量。 特点QSemaphore 是 Qt 框架提供的计数信号量类用于控制同时访问共享资源的线程数量。 用途限制并发线程数量用于解决⼀些资源有限的问题。 QSemaphore semaphore(2); //同时允许两个线程访问共享资源 //在需要访问共享资源的线程中 semaphore.acquire(); //尝试获取信号量若已满则阻塞 //访问共享资源 //… semaphore.release(); //释放信号量 //在另⼀个线程中进⾏类似操作总结 本文详细介绍了Qt多线程的各个方面从基础概念到实际应用再到线程安全和同步机制的讨论。首先我们概述了Qt多线程与Linux线程的关系并比较了Qt、C11和Linux原生API的优缺点。接着我们深入探讨了QThread的常用API和如何使用线程来执行耗时操作同时强调了Qt中界面更新必须在主线程中进行的原则。 在多线程的使用场景中我们讨论了多线程在客户端开发中的重要性尤其是在提升用户体验方面的作用。随后文章重点讨论了线程安全问题包括加锁机制、读写锁以及条件变量和信号量的使用这些都是确保多线程程序正确运行的关键技术。 最后通过实际代码示例我们展示了如何在Qt中创建和管理线程以及如何使用锁和其他同步机制来处理线程间的通信和数据共享。通过本文的学习开发者应该能够更加自信地在Qt中实现多线程编程编写出既高效又稳定的应用程序。