QT5(16)多线程 Thread

推荐一博客
Qt提供两种多线程方式。一种继承QThread类;另一种采用movetothread。在Qt中采用事件循环(QEvenLoop)处理时间。

一、继承QThread

Qt线程中默认run函数调用exec()执行事件循环。但是如果继承的run函数没有启动事件循环,run函数就不会阻塞。如果我们需要启动线程内的事件循环,就需要手动执行exec()。
注意继承自QThread的类在子线程中只有run()函数部分能够在子线程中运行。其他部分还是在主线程中运行。

#include <QtCore>

class Thread : public QThread
{
private:
    void run()
    {
        qDebug()<<"From worker thread: "<<currentThreadId();
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug()<<"From main thread: "<<QThread::currentThreadId();

    Thread t;
    QObject::connect(&t, SIGNAL(finished()), &a, SLOT(quit()));

    t.start();
    return a.exec();
}

如果run函数没有启用事件循环,那么一般情况下我们通过设置flag来结束进程。启用事件循环exec()后,线程不断做着循环遍历事件队列的工作,调用QThread的quit()或exit()方法使停止线程,尽量不要使用terminate(),会造成资源不能释放,甚至互斥锁还处于加锁状态。其中quit与terminate是槽,可以直接用信号连接关闭线程。线程被终止时,所有等待该线程Finished的线程都将被唤醒。

#include "QThread"
#include "QMutexLocker"
#include "QMutex"
class Thread:public QThread
{
    Q_OBJECT
public:
    Thread();
    void stop();
private:
    bool m_stopFlag;
    QMutex mutex;
protected:
    void run();
};
Thread::Thread()
{
    m_stopFlag = false;
}

void Thread::stop()
{
    QMutexLocker locker(&mutex);
    m_stopFlag = true;
}

void Thread::run()
{
    while(1){
        {
            QMutexLocker locker(&mutex);
            if(m_stopFlag)
                break;
        }
        qDebug()<<"This is in thread["<<currentThreadId()<<"]."<<(int)currentThread();
        sleep(2);
    }
    m_stopFlag = false;
}

二、movetothread

目前的推荐做法:子类继承QObject,然后使用movetothread将对象交给子线程,当信号发出后,Qt会将SLOT函数提交给子线程,放在子线程中执行。类的SLOT的函数都能够在线程中执行。

include <QtCore>
class Worker : public QObject
{
    Q_OBJECT
private slots:
    void onTimeout()
    {
        qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
    }
};

#include "main.moc"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug()<<"From main thread: "<<QThread::currentThreadId();

    QThread t;
    QTimer timer;
    Worker worker;

    QObject::connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
    timer.start(1000);

    worker.moveToThread(&t);

    t.start();

    return a.exec();
}

三、connect最后一个参数

参数解释
Qt::AutoConnection默认连接方式,如果信号与槽在同一线程,等同于直接连接;在不同线程,等同于队列连接。
Qt::DirectConnection无论槽函数所属对象在哪个线程,槽函数都在信号的线程内执行,使用该连接,槽将会不在线程执行。
Qt::QueuedConnection槽函数在对象的当前线程中按照队列顺序执行。如果线程停止,就会等待下一次启动线程时再按队列顺序执行。
Qt:: BlockingQueuedConnection只有槽函数在线程执行完才会返回,否则发送线程也会等待。
Qt::UniqueConnection与AutoConnect相同,只是不能重复连接相同的信号和槽。
Qt::AutoCompatConnection兼容老版本

附上练手的百度私链破解程序(已失效,目前多次密码出错,链接404错误。)

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt Creator 多线程读取文件到程序显示 利用QT Creator多任务读取一个文档到程序里 为了防止直接读取文件里的内容太大而发生卡顿,于是多线程读取将更高效的解决这个问题。 效果图如下: 其中pro文件无需改动,默认就好,头文件h里面的内容为 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MyObj; class MyObj : public QObject { Q_OBJECT public: MyObj(); //新的线程 signals: void toLine(QString line); private slots: void doWork(); }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void appendText(QString); //定义一个槽 private: Ui::MainWindow *ui; QThread *t; MyObj *obj; }; #endif // MAINWINDOW_H 而MAIN主文件的内容为了防止中文乱码做了如下修改: #include "mainwindow.h" #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); //设置中文字体 防止乱码 a.setFont(QFont("Microsoft Yahei", 9)); //设置中文编码 #if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) #if _MSC_VER QTextCodec *codec = QTextCodec::codecForName("GBK"); #else QTextCodec *codec = QTextCodec::codecForName("UTF-8"); #endif QTextCodec::setCodecForLocale(codec); QTextCodec::setCodecForCStrings(codec); QTextCodec::setCodecForTr(codec); #else QTextCodec *codec = QTextCodec::codecForName("UTF-8"); QTextCodec::setCodecForLocale(codec); #endif MainWindow w; w.show(); return a.exec(); } 接下来重点来了,源文件CPP里为 #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); t = new QThread(); //QThread obj = new MyObj(); obj->moveToThread(t); qDebug()<<"main thread:"<<QThread::currentThread(); connect(t,SIGNAL(started()), obj, SLOT(doWork())); connect(obj,SIGNAL
### 回答1: Qt5 中的 QObject 类提供了一个名为 moveToThread() 的函数,可以将对象从当前线程移动到另一个线程。这样可以使用多线程来并行处理任务,提高程序的性能。使用 moveToThread() 函数时需要注意,被移动到的线程需要先启动,否则会产生错误。 ### 回答2: Qt5是一个开发跨平台应用程序的框架,其中的多线程技术可以使程序效率更高。Qt5中的多线程模型做了大量的工作来简化一个活动对象(也就是一个线程)在多个线程之间被转移时的代码。其中一种常见的实现方式是使用QThread类。 在Qt5中可以使用QThread类来创建一个线程,从而使主线程和子线程可以并发执行。但是,如果在子线程中访问主线程中的UI控件或者调用主线程中的函数的话,就需要使用Qt5中的MovetoThread机制。因为Qt5默认情况下,只有创建控件的主线程才可以操作该控件,如果在其他线程中修改控件,会导致程序崩溃。 MovetoThread的机制就是将主线程中的控件或者函数移动到子线程中执行,以避免跨线程操作UI控件造成崩溃的问题。具体操作步骤如下: 1. 通过QObject::moveToThread()函数将控件或对象移到新线程中; 2. 创建新线程对象; 3. 将需要在新线程中执行的操作绑定到信号槽上。 需要注意的是: 1. 使用MovetoThread机制时,控件必须继承自QObject,才能使用moveToThread()函数; 2. 通过signal-slot方式通信时,可以使用多种数据类型,如QString、QByteArray等,但是不能传递QWidget类型的对象; 3. 在线程中,应该重写run()函数来定义需要执行的操作,但避免直接修改UI控件; 4. 在线程停止之前,需要通过wait()或quit()减轻其负担。 总之,Qt5的MovetoThread机制可以更好地实现多线程操作,同时克服跨线程操作控件的问题,确保程序的稳定性。 ### 回答3: Qt5多线程中,MoveToThread是一个非常实用的功能。它可以让一个QObject对象从一个线程移动到另一个线程,从而实现线程的切换。在之前的Qt版本中,多线程操作通常需要在各个线程自己的对象中进行,但是Qt5的扩展使得利用其他线程的对象变得更为容易。 其实Qt5关于多线程MoveToThread功能是通过类QThread的方法moveToThread子类继承QThread可以完成该操作,该类的该方法会将对象加入线程队列,等待目标线程执行。同时需要注意到的是,该方法只能被主线程调用。 使用该功能的目的通常是为了防止UI线程(主线程)被阻塞,因为UI线程负责响应用户输入事件,并显示图形化结果,一旦UI线程被长时间阻塞,那么整个应用程序将会卡住,导致非常不友好的用户体验。这是非常不可接受的,因此我们需要将耗时的操作从UI线程中移除,以允许UI线程响应其他事件。 MoveToThread的程序代码通常如下,可以将需要部署到工作线程的对象定义为堆对象(QPointer)或共享指针(std::shared_ptr),以便在工作线程执行时避免对象的销毁: ``` Worker* worker = new Worker; //需要其他线程执行的对象(必须是QObject的子类) QThread* workerThread = new QThread; //启动工作线程 worker->moveToThread(workerThread); workerThread->start(); ``` 然而,需要注意的是,如果QObject派生类高度依赖于QObject的常规信号槽机制,则应该通过(QMetaObject::invokeMethod)调用该方法,而不能直接从工作线程对该对象调用该方法,使得能够进程线程的切换。 总的来说,Qt5多线程MoveToThread功能使得程序在实现多线程操作时更为高效、更易于维护,避免了因为长时间阻塞UI线程而导致的应用程序卡顿或死机。但是,在实现该功能时,程序员需要小心处理程序设计,避免其他线程啊阻塞工作线程并确保工作线程的任务安全。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值