【Qt】系统相关(3)——多线程

📅 2026/7/6 2:51:40
【Qt】系统相关(3)——多线程
【Qt】系统相关3——多线程1. Qt多线程概念2. 线程安全2.1 互斥锁2.2 条件变量2.3 信号量1. Qt多线程概念首先说明一下Qt中的多线程和linux中的多线程是一个东西只不过Qt中对其进行了封装在Qt中可以更方便的使用。在Qt中多线程的处理一般是通过QThread类来实现。QThread代表一个在应用程序中可以独立控制的线程也可以和进程中的其他线程共享数据。QThread对象管理程序中的一个控制线程。在Qt中想要创建线程首先就要创建出y8geQThread的实例并且在创建线程的时候重点要制定线程的入口函数而这个入口函数是通过创建一个QThread的子类然后重写其中的run函数来起到指定入口函数的方式这里就用到了多态就有点类似于我们之前学的事件。QThtread常用APIAPI作用run()线程的入口函数start()通过调用ru0开始执行线程。操作系统将根据优先级参数调度线程。如果线程已经在运行这个函数什么也不做。currentThread()返回一个指向管理当前执行线程的QThread的指针。isRunning()如果线程正在运行则返回true;否则返回false。sleep()/msleep()/usleep()使线程休眠单位为秒/毫秒/微秒wait()阻塞线程直到满足以下任何一个条件与此QThread对象关联的线程已经完成执行即当它从run0返回时。如果线程已经完成这个函数将返回true。如果线程尚未启动它也返回true。已经过了几毫秒。如果时间是ULONG_MAX(默认值)那么等待永远不会超时线程必须从run0返回)。如果等待超时此函数将返回false。这提供了与POSIX pthread_join0函数类似的功能。终止线程的执行。线程可以立即终止也可以不立即终止这取决于操作系统的调terminate()度策略。在terminate0之后使用QThread:wait0来确保。finished()当线程结束时会发出该信号可以通过该信号来实现线程的清理工作。示例通过创建一个线程来实现一个定时器在之前的事件章节中是通过QTimer和QTimerEvetn来实现的定时器而本章节同样可以使用线程的方式来实现。具体步骤就是创建一个线程类继承自QThread然后重写run函数在run函数中实现一个for循环并且每隔一秒中就发射一个信号而信号由主线程接收也就相当于实现了每隔一秒钟的定时器。创建一个继承自QThread的类thread.h头文件#includeQWidget#includeQThreadclass Thread:public QThread{Q_OBJECT public:Thread();// 重写runvoidrun();signals:// 自定义信号voidnotify();};thread.cpp源文件voidThread::run(){// 在run中也就是在线程中不能直接修改界面而是要主线程才能修改界面for(inti0;i10;i){// sleep本身是QThread的成员函数可以直接调用sleep(1);// 发出一个信号emitnotify();}}widget.h头文件class Widget:public QWidget{Q_OBJECT public:Widget(QWidget*parentnullptr);~Widget();public slots:voidhandel();private:Ui::Widget*ui;Thread thread;};widget.cpp源文件#includeui_widget.hWidget::Widget(QWidget*parent):QWidget(parent),ui(new Ui::Widget){ui-setupUi(this);// 关联线程connect(thread,Thread::notify,this,Widget::handel);// 启动线程thread.start();}Widget::~Widget(){delete ui;}voidWidget::handel(){intvalueui-lcdNumber-intValue();--value;ui-lcdNumber-display(value);}2. 线程安全实现线程互斥和同步常用的类有互斥锁QMutex、QMutexLocker条件变量QWaitCondition信号量QSemaphore读写锁QReadLocker、QWriteLocker、QReadWriteLock2.1 互斥锁互斥锁是一种保护和防止多个线程同时访问同一对象实例的方法在Qt中互斥锁主要是通过QMutex类来处理。QMutex特点QMutex是Qt框架提供的互斥锁类用于保护共享资源的访问实现线程间的互斥操作。用途在多线程环境下通过互斥锁来控制对共享数据的访问确保线程安全。**示例**创建两个线程对临界资源num进行加法操作thread.h#includeQWidget#includeQThread#includeQMutexclass Thread:public QThread{Q_OBJECT public:Thread();// 重写runvoidrun();// 声明两个静态成员staticintnum;staticQMutex mutex;};thread.cpp#includethread.h// 定义intThread::num0;QMutex Thread::mutex;Thread::Thread(){}voidThread::run(){for(inti0;i100;i){mutex.lock();num;mutex.unlock();}}widget.cpp#includeQDebugWidget::Widget(QWidget*parent):QWidget(parent),ui(new Ui::Widget){ui-setupUi(this);// 创建两个线程Thread t1;Thread t2;// 启动线程t1.start();t2.start();// 线程等待让主线程等待这两个线程结束这里需要注意的是如果没有线程等待的话启动程序是由三个线程的一个是主线程两个创建// 的线程而当创建的线程启动的时候主线程也会接着往下走那么当执行的qDebug的时候可能两个线程还没有结束所以打印出的结果// 就会出错。t1.wait();t2.wait();qDebug()Thread::num;}QMutexLocker特点QMutexLocker是QMutex的辅助类使用RAl(Resource Acquisition Is Initialization)方式对互斥锁进行上锁和解锁操作。用途简化对互斥锁的上锁和解锁操作避免忘记解锁导致的死锁等问题。于是上面的代码就可以写成thread.cpp#includethread.h// 定义intThread::num0;QMutex Thread::mutex;Thread::Thread(){}voidThread::run(){for(inti0;i100;i){QMutexLockerlocker(mutex);num;}}QReadWriteLocker、QReadLocker、.QWriteLocker特点QReadWriteLock是读写锁类用于控制读和写的并发访问。QReadLocker用于读操作上锁允许多个线程同时读取共享资源。QWriteLocker用于写操作上锁只允许一个线程写入共享资源。用途在某些情况下多个线程可以同时读取共享数据但只有一个线程能够进行写操作。读写锁提供了更高效的并发访问方式。QReadWriteLock rwLock;//在读操作中使⽤读锁{QReadLockerlocker(rwLock);//在作⽤域内⾃动上读锁//读取共享资源//...}//在作⽤域结束时⾃动解读锁//在写操作中使⽤写锁{QWriteLockerlocker(rwLock);//在作⽤域内⾃动上写锁//修改共享资源//...}//在作⽤域结束时⾃动解写锁2.2 条件变量在多线程编程中假设除了等待操作系统正在执行的线程之外某个线程还必须等待某些条件满足才能执行这时就会出现问题。这种情况下线程会很自然地使用锁的机制来阻塞其他线程因为这只是线程的轮流使用并且该线程等待某些特定条件人们会认为需要等待条件的线程在释放互斥锁或读写锁之后进入了睡眠状态这样其他线程就可以继续运行。当条件满足时等待条件的线程将被另一个线程唤醒。在Qt中专门提供了QWaitCondition类来解决像上述这样的问题。特点QWaitCondition是Qt框架提供的条件变量类用于线程之间的消息通信和同步。用途在某个条件满足时等待或唤醒线程用于线程的同步和协调。QMutex mutex;QWaitCondition condition;//在等待线程中mutex.lock();//检查条件是否满⾜若不满⾜则等待while(!conditionFullfilled()){condition.wait(mutex);//等待条件满⾜并释放锁}//条件满⾜后继续执⾏//...mutex.unlock();//在改变条件的线程中mutex.lock();//改变条件changeCondition();condition.wakeAll();//唤醒等待的线程mutex.unlock();2.3 信号量有时在多线程编程中需要确保多个线程可以相应的访问一个数量有限的相同资源。例如运行程序的设备可能是非常有限的内存因此我们更希望需要大量内存的线程将这一事实考虑在内并根据可用的内存数量进行相关操作多线程编程中类似问题通常用信号量来处理。信号量类似于增强的互斥锁不仅能完成上锁和解锁操作而且可以跟踪可用资源的数量。特点QSemaphore是Qt框架提供的计数信号量类用于控制同时访问共享资源的线程数量。用途限制并发线程数量用于解决一些资源有限的问题。QSemaphoresemaphore(2);//同时允许两个线程访问共享资源//在需要访问共享资源的线程中semaphore.acquire();//尝试获取信号量若已满则阻塞//访问共享资源//...semaphore.release();//释放信号量//在另⼀个线程中进⾏类似操作