首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

等待QThread时UI会阻塞/如何正确使用QThread

基础概念

QThread 是 Qt 框架中的一个类,用于创建和管理线程。Qt 是一个跨平台的 C++ 应用程序框架,广泛应用于桌面和移动应用程序开发。QThread 允许你在单独的线程中执行耗时的操作,以避免阻塞主线程(通常是 UI 线程),从而保持界面的响应性。

相关优势

  1. 避免 UI 阻塞:通过将耗时操作放在单独的线程中,可以防止 UI 线程被阻塞,保持界面的流畅性。
  2. 提高性能:多线程可以提高应用程序的整体性能,特别是在处理大量数据或复杂计算时。
  3. 更好的资源管理:线程可以更有效地管理系统资源,避免单一线程的资源瓶颈。

类型

QThread 本身是一个抽象类,通常通过继承 QThread 并重写 run() 方法来实现自定义线程逻辑。此外,Qt 还提供了 QObject::moveToThread() 方法,允许将一个 QObject 及其子对象移动到指定的线程中。

应用场景

  1. 耗时操作:如文件读写、网络请求、复杂计算等。
  2. 定期任务:如定时器、数据更新等。
  3. 并发处理:如多用户同时操作、多任务并行处理等。

问题及解决方法

问题:等待 QThread 时 UI 会阻塞

原因:当你在主线程中调用 QThreadwait() 方法或使用 QThread::finished() 信号时,主线程会等待该线程完成,从而导致 UI 阻塞。

解决方法

  1. 使用信号和槽机制:通过信号和槽机制,将线程的完成信号连接到主线程的槽函数,而不是直接等待线程完成。
代码语言:txt
复制
// 自定义线程类
class MyThread : public QThread {
    Q_OBJECT
public:
    MyThread(QObject *parent = nullptr) : QThread(parent) {}

protected:
    void run() override {
        // 耗时操作
        emit finished();
    }

signals:
    void finished();
};

// 主线程代码
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget window;
    QPushButton button("Start Thread");
    QVBoxLayout layout(&window);
    layout.addWidget(&button);

    MyThread thread;

    QObject::connect(&button, &QPushButton::clicked, [&thread]() {
        thread.start();
    });

    QObject::connect(&thread, &MyThread::finished, &app, &QApplication::quit);

    window.show();
    return app.exec();
}
  1. 使用 QRunnableQThreadPoolQRunnable 是一个接口,用于定义可运行的任务,QThreadPool 是一个线程池,用于管理和调度这些任务。
代码语言:txt
复制
// 自定义任务类
class MyRunnable : public QRunnable {
public:
    void run() override {
        // 耗时操作
    }
};

// 主线程代码
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget window;
    QPushButton button("Start Task");
    QVBoxLayout layout(&window);
    layout.addWidget(&button);

    QThreadPool pool;
    pool.setMaxThreadCount(10);

    QObject::connect(&button, &QPushButton::clicked, [&pool]() {
        MyRunnable *task = new MyRunnable;
        pool.start(task);
    });

    window.show();
    return app.exec();
}

参考链接

通过上述方法,你可以有效地避免在等待 QThread 时 UI 阻塞的问题,并正确地使用多线程来提高应用程序的性能和响应性。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

【QT】Qt 多线程

使用线程 创建线程的步骤: 自定义一个类,继承于 QThread,并且只有⼀个线程处理函数(和主线程不是同⼀个线程),这个线程处理函数主要就是重写父类中的 run() 函数。...示例代码: 1、首先新建 Qt 项目,设计 UI 界面如下,一个 label 和 PushButton: 2、新建一个类,继承于 QThread 类; 3、timethread.h 的程序如下:...这种情况下,线程很自然地使用锁的机制来阻塞其他线程,因为这只是线程的轮流使用,并且该线程等待某些特定条件,人们认为需要等待条件的线程,在释放互斥锁或读写锁之后进⼊了睡眠状态,这样其他线程就可以继续运行...当条件满足等待条件的线程将被另⼀个线程唤醒。 在 Qt 中,专门提供了 QWaitCondition 类来解决像上述这样的问题。...用途:在某个条件满足等待或唤醒线程,用于线程的同步和协调。

11110
  • 【QT】解决继承QThread的子线程导致程序无法关闭&主线程关闭太快导致子线程中的槽方法未执行

    1我使用继承自QThread实现的线程,其中重写run函数,并添加while循环,详见问题1中的代码。...与 Qt::QueuedConnection 相同,除了信号线程阻塞直到槽返回。 如果接收器位于信号线程中,则不得使用此连接,否则应用程序将死锁。...因为使用参数Qt::QueuedConnection被放到了主线程的事件队列中,等待当前代码执行完毕之后被执行. 解决方式 在该发送信号后手动调用事件处理。即,先处理这个。...阻塞线程,直到满足以下任一条件: 与此QThread对象关联的线程已完成执行(即,当它从run()返回)。如果线程已完成,此函数将返回true。如果线程还没有启动,它也返回true。...的第五个参数,Qt根据情况自动的选取。

    95410

    Qt使用多线程的一些心得——1.继承QThread的多线程使用方法

    2.4 如何正确启动一个线程 2.4.1正确的启动一个全局线程(和UI一直存在的线程) 2.4.2 如何启动一个局部线程(用完即释放的线程) 3....这里要记录的是如何正确的创建一个线程,特别是如何正确的退出一个线程。...2.1写一个继承于QThread的线程 本文的重点不是教会你继承run写一个多线程,任何有编程基础的5分钟就能学会使用QThread的方法,本文真正要讲的是后面那几节,如如何安全的退出一个线程,如何开启一个临时线程...在UI线程调用QThread::quit()或QThread::exit()函数会不会停止线程? 在UI线程调用QThread::terminate函数会不会停止线程? 如何正确的退出线程?...真正要注意的是如何ui结束把线程安全退出。

    3.1K11

    QThread介绍

    本篇博客将针对以下几个方面进行讲解 [1]QThread的常用接口以及QThread的实现 [2]QThread的信号事件 [3]QThread执行完后自动释放内存 [4]关闭窗口自动停止线程的运行...运行效果: [2]QThread的信号事件 QThread有两个信号事件,一个是线程开始(run函数被调用之前发出此信号),发出来的,一个是线程结束(在线程将要结束发出此信号)。...究其原因,编程者在编程要明确知道应该用什么同步互斥机制,如何去用这些同步互斥机制。...如果先前有其他线程以写锁方式进行了锁定,则调用这个函数阻塞等待 lockForWrite():以写入方式锁定资源,其他线程不可读,不可写。...如果先前有其他线程以读锁或写锁的方式进行了锁定,调用这个函数阻塞等待。 unlock()解锁,与锁定资源函数成对出现。 tryLockForRead():lockForRead的非阻塞版本。

    1.1K20

    【QT】Qt文件和多线程

    ,不同线程使用Qt::UniqueConnection Qt::DirectConnection 信号发出,槽函数立即在同一线程中执行,适用于信号和槽在同一线程 Qt::QueuedConnection...信号发出,槽函数会被插入到接收对象所属的线程的事件队列中,等待下一次时间循环执行,适用于信号和槽不在同一线程 Qt::BlockingQueuedConnection 信号发出,发送信号的线程会被阻塞...::sleep(1); } } 在这个代码块中,使用了 QMutexLocker 来管理锁,QMutexLocker 会在它的作用范围内自动锁定 mutex,并在 locker 离开作用域(即循环的下一次迭代开始...(2)条件变量 因为在多线程编程中,某些线程需要等待某些条件满足才能执行,此时线程会使用锁的机制来阻塞其他线程,当条件满足等待条件的线程将被另一个线程唤醒 QWaitCondition是Qt框架提供的条件变量类...,用于线程之间的通信和同步,在某个条件满足等待或唤醒线程,用于线程的同步和协调 QMutex mutex; QWaitCondition condition; //等待线程中 mutex.lock(

    8110

    C++ Qt开发:运用QThread多线程组件

    多线程技术在程序开发中尤为常用,Qt框架中提供了QThread库来实现多线程功能。当你需要使用QThread,需包含QThread模块,以下是QThread类的一些主要成员函数和槽函数。...void wait() 等待线程完成。主线程将被阻塞,直到该线程退出。 bool isRunning() const 检查线程是否正在运行。...当你创建一个QThread的实例并调用它的start()方法自动调用run()来执行线程逻辑,如下这样一段代码展示了如何运用线程类。...当 QMutexLocker 对象超出作用域范围自动释放锁。...如果计数器不足,线程将阻塞等待。 bool tryAcquire(int n = 1):尝试获取信号量,如果计数器足够,立即获取并返回 true;否则返回 false。

    24910

    Qt下使用fork创建进程并使用socket通信

    之前在嵌入python解释器的过程中,我们没有处理这样一种情况:当Python解释器正在执行一个阻塞操作(比如socket server 在监听一个客户端连入),这时我们需要终止解释器的运行,该如何操作呢...老规矩,接下来上码: #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include...简单介绍下程序的主体构成:构造函数中使用c创建客户端,使用Qt的类创建服务器。 界面点击start按钮使用fork创建子进程,在进程中客户端向服务器发送数据。...点击stop按钮,父进程向子进程发出kill信号,由于子进程注册了中断信号,所以执行信号函数中的操作。...之后父进程使用 waitpid(childProcessId,NULL,WNOHANG)等待清理子进程,之后进程资源被释放。

    1.7K30

    QThread

    使用wait()来阻塞调用线程,直到另外一个线程执行完成或直到经过指定时间。   ...返回新创建的QThread实例。 注意:调用者获得返回的QThread实例的所有权。 注意:此函数仅在使用c++ 17可用。...请确保terminate()之后使用QThread :: wait()来等待结束。   当线程终止,所有等待线程都将被唤醒。 警告:此功能很危险,不鼓励使用。线程可以在其代码路径中的任何位置终止。...修改数据可以终止线程。导致线程无法自行清理,解锁任何保持的互斥锁等。简而言之,只有在绝对必要的情况下才使用此功能。   ...如果线程尚未启动,它也返回true。 条件2:等待的时间已过。 如果时间是ULONG_MAX(默认值),那么等待将永远不会超时(线程必须从run()返回)。

    1.3K20

    PyQt 线程类 QThread

    PyQt中的线程类 QtCore.QThread使用时继承QThread类 启动界面的线程暂称为UI线程。界面执行命令都在自己的UI线程中。...如果在UI线程中执行网络连接和数据库操作等耗时的操作,界面会被卡住,Windows下有可能会出现“无响应”的警告。 阻塞UI线程降低用户体验和应用稳定性。因此我们可以把耗时操作放在线程中去执行。...QThread代表一个线程,我们可以复写run函数来执行我们要的操作。 QThread可以使用QtCore.pyqtSignal来与界面交互和传输数据。...中使用的信号signal_time = QtCore.pyqtSignal(str, int) 指定了参数str和int 发送信号self.signal_time.emit("Running time:...self.timer_t.signal_time.connect(self.update_timer_tv) 信号连接到方法update_timer_tv(self, text, number),注意信号与方法的参数要一一对应 使用中我们可以定义多种不同的信号

    93220

    QThread

    使用wait()来阻塞调用线程,直到另外一个线程执行完成或直到经过指定时间。   ...返回新创建的QThread实例。 注意:调用者获得返回的QThread实例的所有权。   注意:此函数仅在使用c++ 17可用。    ...请确保terminate()之后使用QThread :: wait()来等待结束。   当线程终止,所有等待线程都将被唤醒。 警告:此功能很危险,不鼓励使用。线程可以在其代码路径中的任何位置终止。...修改数据可以终止线程。导致线程无法自行清理,解锁任何保持的互斥锁等。简而言之,只有在绝对必要的情况下才使用此功能。   ...如果线程尚未启动,它也返回true。 条件2:等待的时间已过。 如果时间是ULONG_MAX(默认值),那么等待将永远不会超时(线程必须从run()返回)。

    2.6K20

    翻译 | 您没有做错(线程)

    年1月22日   这篇文章是关于QThread使用的。...他声称这违反了正确的面向对象设计。这是我不同意的地方。...而且甚至存在泄漏:QThread永远不会退出并被销毁。   我在IRC上被问到一个用户的问题,该用户遵循该示例,以便在线程中运行一些简单的代码。他很难弄清楚如何正确销毁线程。...Qt线程示例threadedfortuneserver是使用此模式运行阻塞操作的示例,并且比使用worker对象的等效示例要简单得多。   ...现在,QtConcurrent有其自身的一系列问题:它与单个线程池绑定,因此如果要运行阻塞操作,它不是一个好的解决方案。在其实现中还存在一些问题,这些问题带来一些性能开销。所有这些都是可以修复的。

    62610

    【Qt】Qt的线程(两种QThread类的详细使用方式)「建议收藏」

    例如,多个线程中某个线程被阻塞,通过QWaitCondition提供的函数wakeOne()和wakeAll()可以唤醒该线程。...使用QtConcurrent创建的程序根据进程数自行调整使用的线程数。 QThread类 简述 QThread类提供了与系统无关的线程。 QThread代表在程序中一个单独的线程控制。...void terminate() [slot] 终止线程,线程可能立即被终止也可能不会,这取决于操作系统的调度策略,使用terminate()之后再使用QThread::wait(),以确保万无一失...当线程被终止后,所有等待中的线程将会被唤醒。 警告:此函数比较危险,不鼓励使用。线程可以在代码执行的任何点被终止。线程可能在更新数据被终止,从而没有机会来清理自己,解锁等等。。。...总之,只有在绝对必要使用此函数。 void requestInterruption() 请求线程的中断。该请求是咨询意见并且取决于线程上运行的代码,来决定是否及如何执行这样的请求。

    7.7K21

    PyQt5 解决界面无响应方案

    在事件循环中,主线程不断地监听并处理用户的输入事件、定时器事件、网络事件等,然后更新UI界面。...如果在主线程执行耗时操作,比如 循环、sleep、wait 异步线程执行 导致 UI 界面进入无响应状态,我们可以采用以下两种方式异步处理:使用QThread 或 QTimer。...界面出现无响应且进度条没有刷新:解决方案为了避免 UI 界面无响应,我们可以采用以下两种方式:使用 QThread 或 QTimer。...未响应在使用 QThread 的案例中,将 on_clicked 方法改为如下写法,同样导致 UI 未响应状态: def on_clicked(self): worker = MyWorker...如果异步线程的任务还没有完成,而主线程的事件循环又需要等待任务完成才能继续执行,那么就会导致GUI线程无响应。这是因为主线程被阻塞等待异步任务的过程中,无法处理事件。

    29920

    Qt线程中使用socket作为客户端通信(二)

    Qt使用线程的方式有两种,一种是上次所说的继承QThread重新实现run()函数,在run()函数中一直循环处理;另一种则是继承QObject并使用moveToThread()函数将对象移到子线程中。...由于继承QThread方式使用的并不规范,Qt官方强烈建议使用继承QObject的方式。...根据之前编写程序得到的结果,在相对复杂的UI设计中,如果socket通信放在住UI中,并且让服务器每间隔10ms发送数据,这样影响UI的响应,所以应将socket接收数据部分放到线程中。...由上次程序得出的结果,使用继承QThread的方式并不可行,所以这次使用继承QObject的形式。经测试得出,继承QObject该方式不会造成UI的卡顿。...以目前我的知识水平来讲,之前在Qt线程中使用socket的方法是不正确的。如果以后遇到新的解决方式,重新更新!

    3.1K40

    python GUI库图形界面开发之PyQt5线程类QThread详细使用方法

    由于PyQt的的跨平台特性,QThread要隐藏所有与平台相关的代码 要使用QThread开始一个线程,可以创建它的一个子类,然后覆盖其它QThread.run()函数 class Thread(QThread...—-建立一个自定义的类(如thread),自我继承自QThread ,并实现其run()方法即可 在使用线程可以直接得到Thread实例,调用其start()函数即可启动线程,线程启动之后,自动调用其实现的...在线程启动和结束之时执行一段代码进行资源的初始化和释放操作,更灵活的使用方法是,在自定义的QThread实例中自定义信号,并将信号连接到指定的槽函数,当满足一定的业务条件发射此信号 QThread类中的常用方法...QThread类中的常用信号 信号 描述 started 在开始执行run函数之前,从相关线程发射此信号 finished 当程序完成业务逻辑,从相关线程发射此信号 QThread使用方法实例...长时间停留在此界面,知道多线程任务完成后,此界面才会动,当耗时程序非常大,就会造成程序运行失败的假象,实际还是在后台运行的,只是没有显示在主窗口的界面上,当然用户体验也就非常差,那么如何解决这个问题呢

    8.3K36

    35.QT-多线程

    const //线程是否结束 bool isRunning() const //线程是否正在运行 bool wait ( unsigned long time = ULONG_MAX ); //阻塞等待线程执行结束...,如果time(单位毫秒)时间结束,线程还未结束,则返回false,否则返回true,如果time= ULONG_MAX,则表示一直等待 多线程示例 class MyThread : public QThread...多线程的互斥QMutex 当一个全局的共有资源被多个线程同时调用时,则称该资源为临界资源,并且该资源需要使用QMutex互斥类,来保证线程间的互斥,避免同一刻访问临界资源而出现意想不到的问题....其中QMutex中关键成员函数如下: void lock(); //获取锁,如果锁已经被其它线程获取,则将会阻塞并While等待锁释放 bool tryLock (); //尝试获取锁, 如果获得了锁,...如果n是不可用的,这个调用将阻塞,直到有足够的资源可用为止。 void tryAcquire ( int n = 1 ); //尝试获取由信号量保护的n个资源,并在成功返回true。

    1.3K30
    领券