QT多线程(主动挂起线程)

简介: QT多线程(主动挂起线程)

前言

本篇文章来讲解一下QT中如何主动挂起线程,在不想让一个线程运行的时候我们应该如何让线程挂起呢?我们都知道使用sleep函数可以让线程挂起一段时间,但是一段时间过后线程又继续运行,那么有什么方法可以让线程在特定条件下挂起,特定条件下运行吗?


一、线程的挂起态

在Qt中,线程可以通过调用 QThread::sleep() 函数进入挂起状态。QThread::sleep() 函数会导致线程在指定的毫秒数内休眠,进入睡眠状态,等待指定的时间后再继续运行。

线程的挂起状态常用于等待某个事件的发生,比如等待信号的到来、等待定时器的触发、等待文件的读写操作完成等。当线程挂起时,它会主动放弃 CPU 的时间片,以节约系统资源。

在Qt中,还可以通过将线程阻塞在某个对象上来实现挂起状态。比如,可以通过调用 QWaitCondition::wait() 函数将线程阻塞在某个条件变量上,等待其他线程对该条件变量发出信号后再继续执行。

需要注意的是,线程在挂起状态下不会停止,仍然会占用系统资源。因此,在使用线程挂起功能时,需要确保挂起的时间不会过长,以避免降低系统的性能和可靠性。

此外,需要注意线程挂起状态的使用场景和时机。线程挂起过程中不会处理任何事件,包括定时器事件、键盘事件、鼠标事件等,因此,如果在线程中进行长时间的阻塞或挂起,可能会导致 UI 界面无响应,影响用户体验。因此,建议在非必要情况下尽量避免使用线程挂起功能,或者通过线程间通信等机制来替代线程挂起。

二、QWaitCondition

在Qt中,QWaitCondition 是一个用于线程同步的对象,它可以让一个线程等待或者阻塞在一个特定的条件上,直到被其他线程唤醒。

QWaitCondition 的使用通常涉及以下三个对象:

条件变量(QWaitCondition),用来等待和唤醒线程。

互斥锁(QMutex),用来保护条件变量。

通知对象(QMutexLocker),用来通知和等待。

使用 QWaitCondition 时需要注意以下几点:

线程只有在持有相应的互斥锁时才能调用 QWaitCondition::wait() 函数;在阻塞期间会释放互斥锁并进入挂起状态。

发送信号之前,必须先获取相应的互斥锁,否则线程不会得到通知。

通过调用 QWaitCondition::wakeOne() 可以唤醒单个线程,调用 QWaitCondition::wakeAll() 可以唤醒所有等待的线程。

等待时,建议使用 while 循环来检查条件是否满足,防止条件非常容易发生变化的情况下出现误唤醒的问题。


三、示例代码

这段程序主要是实现了主线程既可以唤醒ThreadA线程又可以将ThreadA线程挂起的功能。

#include <QtCore/QCoreApplication>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QDebug>
QMutex g_mutex;
QWaitCondition g_waitcondition;
bool ConditionMet = true;
class ThreadA : public QThread
{
protected:
    void run()
    {
        qDebug() << "Thread Begin";
        while(1)
        {
            g_mutex.lock();            
            while(!ConditionMet)
            {
                g_waitcondition.wait(&g_mutex);//先释放锁,再获取锁
                break;
            }
            qDebug() << "ThreadA";
            g_mutex.unlock();
            sleep(1);
        }
        qDebug() << "Thread End";
    }
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    ThreadA t1;
    t1.start();
    int i = 0;
    while(1)
    {
        qDebug() << "Main Thread";
        i++;
        if(i == 5)
        {
            qDebug() << "ThreadA stop";
            g_mutex.lock();
            ConditionMet = false;
            g_mutex.unlock();
        }
        else if(i == 10)
        {
            qDebug() << "wake ThreadA";
            i = 0;
            g_mutex.lock();
            ConditionMet = true;
            g_waitcondition.wakeOne();
            g_mutex.unlock();
        }
        QThread::sleep(1);
    }
    return a.exec();
}

总结

QWaitCondition 在多线程编程中具有重要的作用,可以帮助实现线程之间的同步和通信,也是Qt中高效使用多线程的关键。

相关文章
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
48 1
C++ 多线程之初识多线程
|
29天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
19 3
|
29天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
18 2
|
29天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
30 2
|
29天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
34 1
|
29天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
37 1
|
29天前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
25 1
|
1月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
47 6
|
1月前
|
存储 运维 NoSQL
Redis为什么最开始被设计成单线程而不是多线程
总之,Redis采用单线程设计是基于对系统特性的深刻洞察和权衡的结果。这种设计不仅保持了Redis的高性能,还确保了其代码的简洁性、可维护性以及部署的便捷性,使之成为众多应用场景下的首选数据存储解决方案。
41 1
|
1月前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
25 0
C++ 多线程之线程管理函数