精华内容
下载资源
问答
  • QThread

    2019-11-27 20:41:00
    这篇主要是讲解QThread 相关,他不是一篇聚集性讲解某个知识点,而是笼统的讲解我在QThread中遇到的困惑点,以及整理我自己相关理解的知识点。 QThread不是线程? QThread 类只是去控制管理线程的类与接口,通过...

    序言

    这篇主要是讲解QThread 相关,他不是一篇聚集性讲解某个知识点,而是笼统的讲解我在QThread中遇到的困惑点,以及整理我自己相关理解的知识点。

    QThread不是线程?

    QThread 类只是去控制管理线程的类与接口,通过start启动新的线程。
    QThread 是用来管理线程的,它所依附的线程和它管理的线程并不是同一个东西。
    QThread 所依附的线程,就是执行 QThread t(0) 或 QThread * t=new QThread(0) 的线程。也就是主线程
    QThread 管理的线程,就是 run 启动的线程。也就是次线程
    因为QThread的对象依附在主线程中,所以他的slot函数会在主线程中执行,而不是次线程。除非:
    QThread 对象依附到次线程中(通过movetoThread)
    slot 和信号是直接连接,且信号在次线程中发射

    QThread 函数误解

    1. sleep()
      它有三种类型分别是
      void QThread::sleep ( unsigned long secs ) [Static Public Members]
      void QThread::msleep ( unsigned long msecs ) [Static Public Members]
      void QThread::usleep ( unsigned long usecs ) [Static Public Members]
      控制秒,毫秒,微秒。其Qt文档是这么说的。
    Forces the current thread to sleep for secs seconds.
    

    开始我以为是QThread所启动的线程休眠,但是经我测试好像是启动QThread开辟的线程--------依附(或者调用)的线程(一般是主线程)。如果想休眠QThread管理的线程那就在其管理线程调用sleep();

    1. wait()
    Blocks the thread until either of these conditions is met:
    1. The thread associated with this QThread object has finished execution (i.e. when it returns from run()). This function will return true if the thread has finished. It also returns true if the thread has not been started yet.
    2. time milliseconds has elapsed. If time is ULONG_MAX (the default), then the wait will never timeout (the thread must return from run()). This function will return false if the wait timed out.
    This provides similar functionality to the POSIX pthread_join() function.
    

    阻塞所依附的线程直到管理的线程退出exec()或者时间ms过去。一般等thread退出exec或者时间过去。

    QThread slot函数所在的线程

    1. 对于QThread派生子类而言,start启动后,只有run中函数在另一个线程中执行,其他构造与slot都在所依附的线程中执行。
    2. 通过moveToThread()函数,可以改变线程的关联性,可以将object对象从其所依附的线程中move到另一个线程。注意不能将
    3. slot是可以改变的,一般是在默认的所依附的线程中执行,
      但是通过connect连接方式是可以改变slot线程的。
      connect(Dummy::GetInstance(), SIGNAL(sig()), this, SLOT(slot_thread())/,Qt::DirectConnection/);
    class Dummy:public QObject
    {
        Q_OBJECT
    public:
        static Dummy* GetInstance();
    
        Dummy(QObject* parent=0)
            :QObject(parent)
        {
              qDebug()<<"thread Dummy():"<<QThread::currentThreadId();
        }
    
        void operate()
        {
             qDebug()<<__FUNCTION__<<" thread "<<QThread::currentThreadId();
        }
    public slots:
        void emitsig()
        {
            qDebug()<<__FUNCTION__<<" thread "<<QThread::currentThreadId();
            emit sig();
        }
    signals:
        void sig();
    private:
        static Dummy* m_sInstance;
    };
    
    class Thread:public QThread
    {
        Q_OBJECT
    public:
        Thread(QObject* parent=0):QThread(parent)
        {
    //        moveToThread(this);
            qDebug()<<"Thread Thread():"<<currentThreadId();
            //构造函数在生成依附对象执行
        }
    public slots:
        void slot_thread()
        {
            qDebug()<<"from thread slot_thread:" <<currentThreadId();
        }
    signals:
        void sig();
    protected:
        void run()
        {
            QEventLoop loop;
            qDebug()<<" Thread run(): "<<currentThreadId();
    //        Dummy dummy;
    //        connect(&dummy, SIGNAL(sig()), this, SLOT(slot_thread()),Qt::DirectConnection);
    //        dummy.emitsig();
            //------------------------------------------//
            connect(Dummy::GetInstance(), SIGNAL(sig()), this, SLOT(slot_thread())/*,Qt::DirectConnection*/);
            Dummy::GetInstance()->emitsig();
            Dummy::GetInstance()->operate();
            loop.exec();
            //exec()之后的不在运行 除非退出
            //qDebug()<<" exec Thread run(): "<<currentThreadId();
        }
    };
    

    结果
    在这里插入图片描述

         connect(Dummy::GetInstance(), SIGNAL(sig()), this, SLOT(slot_thread()),Qt::DirectConnection);
    

    结果
    在这里插入图片描述
    网址参考

    展开全文
  • Qthread

    2020-10-18 21:59:02
    QThread详解 回顾Qt之线程(QThread),里面讲解了如何使用线程,但还有很多人留言没有看明白,那么今天我们来一起瞅瞅关于QThread管理线程的那些事儿。。。 一、线程管理 1、线程启动void start...

    随笔 - 607  文章 - 0  评论 - 21  QThread详解 回顾Qt之线程(QThread),里面讲解了如何使用线程,但还有很多人留言没有看明白,那么今天我们来一起瞅瞅关于QThread管理线程的那些事儿。。。
    一、线程管理
    1、线程启动void start(Priority priority = InheritPriority)调用后会执行run()函数,但在run()函数执行前会发射信号started(),操作系统将根据优先级参数调度线程。如果线程已经在运行,那么这个函数什么也不做。优先级参数的效果取决于操作系统的调度策略。特别是那些不支持线程优先级的系统优先级将会被忽略(例如在Linux中,更多细节请参考http://linux.die.net/man/2/sched_setscheduler)。 2、线程执行int exec()进入事件循环并等待直到调用exit(),返回值是通过调用exit()来获得,如果调用成功则范围0。virtual void run();线程的起点,在调用start()之后,新创建的线程就会调用这个函数,默认实现调用exec(),大多数需要重新实现这个功能,便于管理自己的线程。该方法返回时,该线程的执行将结束。 3、线程退出void quit()告诉线程事件循环退出,返回0表示成功,相当于调用了QThread::exit(0)。void exit(int returnCode = 0)告诉线程事件循环退出。调用这个函数后,线程离开事件循环后返回,QEventLoop::exec()返回returnCode,按照惯例0表示成功,任何非0值表示失败。void terminate()终止线程,线程可能会立即被终止也可能不会,这取决于操作系统的调度策略,使用terminate()之后再使用QThread::wait()确保万无一失。当线程被终止后,所有等待中的线程将会被唤醒。警告:此功能比较危险,不鼓励使用。线程可以在代码执行的任何点被终止。线程可能在更新数据时被终止,从而没有机会来清理自己,解锁等等。。。总之,只有在绝对必要时使用此功能。建议:一般情况下,都在run函数里面设置一个标识符,可以控制循环停止。然后才调用quit函数,退出线程。 4、线程等待void msleep(unsigned long msecs)强制当前线程睡眠msecs毫秒void sleep(unsigned long secs)强制当前线程睡眠secs秒void usleep(unsigned long usecs)强制当前线程睡眠usecs微秒bool wait(unsigned long time = ULONG_MAX);线程将会被阻塞,等待time毫秒。和sleep不同的是,如果线程退出,wait会返回。 5、线程状态    bool isFinished() const        线程是否结束    bool isRunning() const        线程是否正在运行 6、线程优先级    void setPriority(Priority priority)    这个函数设置正在运行线程的优先级。如果线程没有运行,此功能不执行任何操作并立即返回。使用的start()来启动一个线程具有特定的优先级。    优先级参数可以是QThread::Priority枚举除InheritPriortyd的任何值。    Priority priority() const    下面来看下优先级中的各个枚举值:ConstantValueDescriptionQThread::IdlePriority0没有其它线程运行时才调度.QThread::LowestPriority1比LowPriority调度频率低.QThread::LowPriority2比NormalPriority调度频率低.QThread::NormalPriority3操作系统默认的默认优先级.QThread::HighPriority4比NormalPriority调度频繁.QThread::HighestPriority5比HighPriority调度频繁.QThread::TimeCriticalPriority6尽可能频繁的调度.QThread::InheritPriority7使用和创建线程同样的优先级. 这是默认值.  二、主线程、次线程在Qt之线程(QThread)一节中我介绍了QThread 的两种使用方法:1、子类化 QThread(不使用事件循环)。这是官方手册、例子以及相关书籍中都介绍的一种常用的方法。a. 子类化 QThreadb. 重载 run 函数,run函数内有一个while或for的死循环(模拟耗时操作)c. 设置一个标记为来控制死循环的退出。 2、子类化 QObjecta. 子类化 QObjectb. 定义槽函数c. 将该子类的对象moveToThread到新线程中 run 对于线程的作用相当于main函数对于应用程序。它是线程的入口,run的开始和结束意味着线程的开始和结束。采用这两种做法,毫无疑问都会在次线程中运行(这里说的是,run中的逻辑以及子类化QObject后连接通过moveToThread然后连接到QThread的started()信号的槽函数,这个下面会详细讲解)。那么,线程中的槽函数是怎么运行的呢?说到信号与槽,大家应该再熟悉不过了,包括我,特别喜欢使用自定义信号与槽,感觉用起来特方便、特棒。。。经常使用,你能否100%的使用正确?你了解它的高级用法吗?1、你是否在多次connect,还发现不了为什么槽函数会执行那N多次。2、你是否了解disconnect3、你是否了解connect中的第五个参数 Qt::ConnectionType关于connect、disconnect信号、槽的使用可参考:Qt之信号与槽。既然谈到线程这里需要重点说下Qt::ConnectionType(信号与槽的传递方式)ConstantValueDescriptionQt::AutoConnection0自动连接:(默认值)如果信号在接收者所依附的线程内发射,则等同于直接连接。如果发射信号的线程和接受者所依附的线程不同,则等同于队列连接。Qt::DirectConnection1直接连接:当信号发射时,槽函数将直接被调用。无论槽函数所属对象在哪个线程,槽函数都在发射信号的线程内执行。Qt::QueuedConnection2队列连接:当控制权回到接受者所依附线程的事件循环时,槽函数被调用。槽函数在接收者所依附线程执行。也就是说:这种方式既可以在线程内传递消息,也可以跨线程传递消息Qt::BlockingQueuedConnection3与Qt::QueuedConnection类似,但是会阻塞等到关联的slot都被执行。这里出现了阻塞这个词,说明它是专门用来多线程间传递消息的。 举例:MyObject.h#ifndef MYOBJECT_H
    #define MYOBJECT_H

    #include

    class MyObject : public QObject
    {
    Q_OBJECT

    public:
    explicit MyObject(QObject *parent = 0);

    public slots:
    void start();
    };

    #endif // MYOBJECT_HMyObject.cpp#include “MyObject.h”
    #include
    #include

    MyObject::MyObject(QObject *parent)
    QObject(parent)
    {

    }

    void MyObject::start()
    {
    qDebug() << QString(“my object thread id:”) << QThread::currentThreadId();
    }
    main.cpp#include “MyObject.h”
    #include
    #include
    #include

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);

    qDebug() << QString("main thread id:") << QThread::currentThreadId();
    
    MyObject object;
    QThread thread;
    object.moveToThread(&thread);
    QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()));
    thread.start();
    
    return a.exec();
    

    } 查看运行结果:  “main thread id:” 0xf08  “my object thread id:” 0x216c    显然主线程与槽函数的线程是不同的(你可以多次尝试,屡试不爽。。。),因为moveToThread后MyObject所在的线程为QThread,继上面介绍的thread.start()执行后首先会发射started()信号,也就是说started()信号发射是在次线程中进行的,所以无论采取Qt::AutoConnection、Qt::DirectConnection、Qt::QueuedConnection哪种连接方式,主线程与槽函数的线程都是不同的。 1、修改代码如下: MyObject object;
    QThread thread;
    //object.moveToThread(&thread);
    QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::DirectConnection);
    thread.start();查看运行结果:  “main thread id:” 0x2688  “my object thread id:” 0x2110     显然主线程与槽函数的线程是不同的,MyObject所依附的线程为主线程(因为注释掉了moveToThread),继上面介绍的Qt::DirectConnection(无论槽函数所属对象在哪个线程,槽函数都在发射信号的线程内执行)。也就是说started()信号发射是在次线程中进行的,槽函数也是在次线程中进行的,所以主线程与槽函数的线程是不同的。 2、修改代码如下: MyObject object;
    QThread thread;
    //object.moveToThread(&thread);
    QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::QueuedConnection);
    thread.start();查看运行结果:  “main thread id:” 0x24ec  “my object thread id:” 0x24ec     显然主线程与槽函数的线程是相同的,继上面介绍的Qt::QueuedConnection(槽函数在接收者所依附线程执行)。也就是说started()信号发射是在次线程中进行的,但MyObject所依附的线程为主线程(因为注释掉了moveToThread),所以主线程与槽函数的线程必然是相同的。 3、修改代码如下: MyObject object;
    QThread thread;
    //object.moveToThread(&thread);
    QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::AutoConnection);
    thread.start();查看运行结果:  “main thread id:” 0x2700  “my object thread id:” 0x2700     显然主线程与槽函数的线程是相同的,MyObject所依附的线程为主线程(因为注释掉了moveToThread),继上面介绍的Qt::AutoConnection(如果信号在接收者所依附的线程内发射,则等同于直接连接。如果发射信号的线程和接受者所依附的线程不同,则等同于队列连接。)。因为started()信号和MyObject依附的线程不同,所以结果和Qt::QueuedConnection对应的相同,所以主线程与槽函数的线程是相同的。     基本就介绍到这里,QThread使用和上面的大同小异,run里面执行的代码都是在次线程中,如果是QThead的槽函数,那么结论同上!

    展开全文
  • QThread资料

    2018-09-21 16:37:06
    本资源是关于QThread如何正确使用的资源,里面有篇国外分析的资料,讲的很好
  • QThread介绍

    2021-03-17 11:20:20
    Qt对多线程操作有着完整的支持,Qt中通过继承QThread并重写run()方法的方式实现多线程代码的编写。针对线程之间的同步与互斥问题,Qt还提供了QMutex、QReadWriteLock、QwaitCondition、QSemaphore等多个类来实现。 ...

    在程序设计中,为了不影响主程序的执行,常常把耗时操作放到一个单独的线程中执行。Qt对多线程操作有着完整的支持,Qt中通过继承QThread并重写run()方法的方式实现多线程代码的编写。针对线程之间的同步与互斥问题,Qt还提供了QMutex、QReadWriteLock、QwaitCondition、QSemaphore等多个类来实现。

    本篇博客将针对以下几个方面进行讲解

    [1]QThread的常用接口以及QThread的实现

    [2]QThread的信号事件

    [3]QThread执行完后自动释放内存

    [4]关闭窗口时自动停止线程的运行

    [5]QThread的同步与互斥
    [1]QThread的常用接口以及QThread的实现

    定义Qthread需要执行的任务:

    virtual void run()

    编程者需要重写run()函数,在run函数里来实现线程需要完成的任务。

    开始执行线程任务:

    [slot] void QThread::start(QThread::Priority priority = InheritPriority)

    线程休眠:

        //以下三个函数全部是静态成员函数
        void  msleep(unsigned long msecs)
        void  sleep(unsigned long secs)
        void  usleep(unsigned long usecs)

    结束线程执行:

    在run函数里主动结束:

        void  quit()
        void  exit(int returnCode = 0)

    在任何位置强制线程结束:

    [slot] void QThread::terminate()

    不推荐此方法,除非万不得已。在调用此方法后还需调用wait()方法,来等待线程结束并回收资源。

    线程优先级相关:

        //获取线程的优先级
        QThread::Priority  priority() const
         
        //设置线程的优先级
        void  setPriority(QThread::Priority priority)

    判断是否运行:

        //判断是否运行结束
        bool  isFinished() const
         
        //判断是否正在运行
        bool  isRunning() const

    QThread具体实现:

    在这里通过模拟一个耗时的任务来进行说明,在QThread中模拟一个下载任务(每100ms计数+1,直到加到100为止),并在界面上通过QLabel显示出当前下载进度。实现一个自定义QThread的步骤如下:

    ①新创建类TestThread继承QThread

    ②重写run方法

    ③定义TestThread对象并调用该对象的start方法运行

    TestThread.h代码如下:

        #ifndef TESTTHREAD_H
        #define TESTTHREAD_H
         
        #include <QObject>
        #include <QThread>
         
        class TestThread : public QThread
        {
            Q_OBJECT
        public:
            explicit TestThread(QObject *parent = nullptr);
         
        private:
            //重写run方法
            void run();
         
        signals:
            //定义信号
            void ShowDownloadProgress(int progress);
         
        public slots:
        };
         
        #endif // TESTTHREAD_H

    TestThread.cpp代码如下:

        #include "testthread.h"
         
        TestThread::TestThread(QObject *parent) : QThread(parent)
        {
         
        }
         
        void TestThread::run()
        {
            for(int i = 0 ; i <= 100 ; i++)
            {
                QThread::msleep(100);
                ShowDownloadProgress(i);
            }
        }

    其中,在run中进行线程任务的实现,当run函数执行完了,整个线程也就运行结束了。在run函数中用msleep来模拟耗时的过程,用i++来模拟下载进度的增加。每一次循环都会发出ShowDownloadProgress(i)信号,通过信号与槽的绑定,可以在Qt处理线程中完成QLabel数据的更新。

    widget.cpp中线程对象的创建、信号与槽的绑定、线程启动代码如下:

        TestThread *thread = new TestThread(this);
        connect(thread,SIGNAL(ShowDownloadProgress(int)),this,SLOT(ProgressLabelShow(int)));
        thread->start();

    ProgressLabelShow(int)槽函数的具体实现如下:

        void Widget::ProgressLabelShow(int prog)
        {
            ui->ProgressLabel->setText(QString::number(prog) + "%");
        }

    如上代码即实现了在界面上实时显示下载进度。之所以通过发出信号通知Qt处理线程,并在Qt处理线程中完成QLabel显示内容的更新是因为多线程同时操作Qt控件会有一定的危险,有可能导致程序的异常。而在TestThread线程中发出信号通知Qt处理线程,并在Qt处理线程中操作Qt控件的方法无论是在代码稳定性还是代码结构上都是最佳的。

    运行效果:

    [2]QThread的信号事件

    QThread有两个信号事件,一个是线程开始时(run函数被调用之前发出此信号),发出来的,一个是线程结束时(在线程将要结束时发出此信号)。开始和结束信号如下:

        void finished()
        void started()

    [3]QThread执行完后自动释放内存

    QThread执行结束后自动释放内存,是利用finished信号实现的。官方提供的手册的finished信号的介绍中有这样一句话:

        When this signal is emitted, the event loop has already stopped running. No more events will be processed in the thread, except for deferred deletion events. This signal can be connected to QObject::deleteLater(),to free objects in that thread.

    这句话的意思是将finished绑定到QObject::deleteLater()槽函数可以实现线程的自动销毁。

    为了便于看到效果,我们给自定义的TestThread 类加上析构函数,并在里面打印提示信息:

        ~TestThread()
        {
            qDebug() << "~TestThread";
        }

    在widget.cpp中绑定finished信号与QObject::deleteLater():

        TestThread *thread = new TestThread(this);
        connect(thread,SIGNAL(ShowDownloadProgress(int)),this,SLOT(ProgressLabelShow(int)));
        connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()));
        thread->start();

    其中,信号的发送者和接收者都是新创建的thread对象,槽函数为deleteLater(),该槽函数是继承自QObject的。

    程序执行结果:

    可以看到析构函数被自动执行,由此就完成了在线程结束后自动释放线程空间的功能。
    [4]关闭窗口时自动停止线程的运行

    前面有讲到在线程运行结束时自动释放线程控件,然而,在窗口关闭时。为了及时释放系统资源,也需要程序自动停止正在运行的线程,并释放掉空间。通过重写widget类的closeEvent方法可以实现这个目的:

    改写TestThread类如下:

        #ifndef TESTTHREAD_H
        #define TESTTHREAD_H
         
        #include <QObject>
        #include <QThread>
        #include <QDebug>
         
        class TestThread : public QThread
        {
            Q_OBJECT
        public:
            explicit TestThread(QObject *parent = nullptr);
            ~TestThread()
            {
                qDebug() << "~TestThread";
            }
         
            void StopThread();
         
        private:
            //重写run方法
            void run();
            bool stopFlag = false;
         
        signals:
            //定义信号
            void ShowDownloadProgress(int progress);
         
        public slots:
        };
         
        #endif // TESTTHREAD_H

     

        #include "testthread.h"
         
        TestThread::TestThread(QObject *parent) : QThread(parent)
        {
         
        }
         
        void TestThread::run()
        {
            for(int i = 0 ; i <= 100 && !stopFlag ; i++)
            {
                QThread::msleep(100);
                ShowDownloadProgress(i);
            }
        }
        void TestThread::StopThread()
        {
            stopFlag = true;
        }

    其中,新加的stopFlag标志是为了控制线程是否结束,提供StopThread供外部调用。

    在widget.cpp中重写closeEvent方法:

        void Widget::closeEvent(QCloseEvent *event)
        {
            qDebug() << "closeEvent";
            TestThread *thread =  this->findChild<TestThread*>();
            if(thread == nullptr)
                return;
            if(thread->isRunning())
            {
                thread->StopThread();
                thread->wait();
            }
        }

    在closeEvent中直接调用findChild方法得到先前创建的TestThread线程的指针,然后调用StopThread方法将线程的结束标志置为true,最后调用wait方法阻塞等待线程结束。

    运行结果如下:

     
    [5]QThread的同步与互斥

    在多线程编程中,常常会有某些资源被多个线程共用的情况。例如多个线程需要读/写同一个变量,或者一个线程需要等待另一个线程先运行后才可以运行。进程的同步与互斥,在多线程编程中尤为重要。用的好了,既能让程序稳定运行,又能不影响程序运行效率。用的不好就可能导致程序虽然在稳定运行,但效率大大下降。究其原因,编程者在编程时要明确知道应该用什么同步互斥机制,如何去用这些同步互斥机制。对于线程的同步与互斥Qt提供了QMutex、QReadWriteLock、QwaitCondition、QSemaphore等多个类来实现。

    互斥锁:

    QMutex是基于互斥量的线程同步类,QMutex类主要提供了以下几个方法,用于实现互斥操作:

        lock():上锁,如果之前有另一个进程也针对当前互斥量进行了上锁操作,则此函数将一直阻塞等待,直到解锁这个互斥量。

        unlock():解锁,与lock()成对出现。

        tryLock():尝试解锁一个互斥量,该函数不会阻塞等待,成功返回true,失败返回false(其他线程已经锁定了这个互斥量);

    下面是一个利用互斥量来实现的例子:

        int flag;
        QMutex mutex;
         
        void threadA::run()
        {
            ....
            mutex.lock();
            flag = 1;
            mutex.unlock();
            ....
        }
         
        void threadB::run()
        {
            ....
            mutex.lock();
            flag = 2;
            mutex.unlock();
            ....
        }
         
        void threadC::run()
        {
            ....
            mutex.lock();
            flag = 3;
            mutex.unlock();
            ....
        }

    利用互斥锁保护的资源,不允许多个线程同时操作。

    读写锁:

    互斥锁会在某些应用中出现问题,例如多个线程需要去读某一个变量。此时是不需要排队的,可以同时进行读操作。如果用互斥锁来做保护,这会导致不必要的排队现象发生,影响到程序的运行效率。这时,就需要引入读写锁QReadWriteLock。

    QReadWriteLock提供了以下几个方法:

    lockForRead():以只读方式锁定资源,其他线程可读(可以调用lockForRead),不可写(调用lockForWrite将阻塞等待)。如果先前有其他线程以写锁方式进行了锁定,则调用这个函数会阻塞等待

    lockForWrite():以写入方式锁定资源,其他线程不可读,不可写。如果先前有其他线程以读锁或写锁的方式进行了锁定,调用这个函数会阻塞等待。

    unlock()解锁,与锁定资源函数成对出现。

    tryLockForRead():lockForRead的非阻塞版本。

    tryLockForWrite():lockForWrite的非阻塞版本。

    下面是一个用读写锁的例子:

        int flag;
        QReadWriteLock rwLock;
         
        void threadA::run()
        {
            ....
            rwLock.lockForWrite();
            flag = 1;
            rwLock.unlock();
            ....
        }
         
        void threadB::run()
        {
            ....
            rwLock.lockForWrite();
            flag = 2;
            rwLock.unlock();
            ....
        }
         
        void threadC::run()
        {
            ....
            rwLock.lockForRead();
            switch(flag)
            {
                ......
            }
            rwLock.unlock();
            ....
        }
        void threadD::run()
        {
            ....
            rwLock.lockForRead();
            qDebug() << flag;
            ......
            rwLock.unlock();
            ....
        }

    利用读写锁保护的资源,允许多个线程同时读,不允许多个线程在读的同时写,不允许在写的同时读或写。

    基于QWaitCondition的线程同步:

     前面所提到的互斥锁、读写锁,都是通过加锁的方式实现的资源的保护。在资源解锁时,其他线程并不会立刻得到通知。针对这个问题,Qt引入了QWaitCondition类。将QWaitCondition与QMutex或QReadWriteLock相结合可以实现在资源解锁后及时通知并唤醒其他等待进程。

    QWaitCondition提供的方法如下:

        wait(QMutex *lockedMutex, unsigned long time = ULONG_MAX)
        wait(QReadWriteLock *lockedReadWriteLock, unsigned long time = ULONG_MAX):解锁互斥锁或读写锁,并阻塞等待被唤醒。当被唤醒后,重新锁定QMutex或QReadWriteLock

        wakeAll():唤醒所有等待的进程,顺序不确定,由操作系统调度
        wakeOne():唤醒一个等待的进程,唤醒哪一个不确定,由操作系统调度

    QWaitCondition常用于生产/消费者中,一个产生数据的,几个消费数据的。比如键盘的输入,当键盘输入数据后,有多个线程同时对键盘输入的数据做不同的处理,此时就需要用到QWaitCondition来实现。

    全局可用变量的定义

        QWaitCondition keyPressed;
        char c;
        int count;

    线程1:获取键盘的输入

        for(;;){
              c = getchar();
         
              mutex.lock();
              // Sleep until there are no busy worker threads
              while (count > 0) {
                  mutex.unlock();
                  sleep(1);
                  mutex.lock();
              }
              keyPressed.wakeAll();
              mutex.unlock();
          }

    线程2:处理输入数据

         for(;;){
              mutex.lock();
              keyPressed.wait(&mutex);
              ++count;
              mutex.unlock();
         
              do_something_xxxx(c);
         
              mutex.lock();
              --count;
              mutex.unlock();
          }

    线程3:处理输入数据

         for(;;){
              mutex.lock();
              keyPressed.wait(&mutex);
              ++count;
              mutex.unlock();
         
              do_something_xxxxxxxxxxxxx(c);
         
              mutex.lock();
              --count;
              mutex.unlock();
          }

    在本例的线程1中引入了count 是否大于 0的判断,是为了保证每个线程都能够执行完后,再进行键盘输入获取以及唤醒操作。

    利用信号量(QSemaphore)实现的线程同步:

    互斥锁、共享锁都只能针对一个资源进行保护,而不能针对多个类似的资源进行保护。而利用QSemaphore可以做到对多个类似的资源进行保护。

    QSemaphore主要提供了以下几个方法:

        acquire(int n = 1):获取n个资源,如果没有,则阻塞等待,直到有n个资源可用为止。

        release(int n = 1):释放更多资源,如果信号量的资源已全部可用后,调用此函数将增加更多的资源

        bool tryAcquire(int n = 1):尝试获取n个资源,不会阻塞等待,有返回true,无返回false

    简单示例:

        QSemaphore sem(5);      // sem.available() == 5
         
        sem.acquire(3);         // sem.available() == 2
        sem.acquire(2);         // sem.available() == 0
        sem.release(5);         // sem.available() == 5
        sem.release(5);         // sem.available() == 10
         
        sem.tryAcquire(1);      // sem.available() == 9, returns true
        sem.tryAcquire(250);    // sem.available() == 9, returns false

    示例:

    定义的全局变量

        const int DataSize = 100000;
         
        const int BufferSize = 8192;
        char buffer[BufferSize];
         
        QSemaphore freeBytes(BufferSize);
        QSemaphore usedBytes;

    生产者线程:

        class Producer : public QThread
          {
          public:
              void run() override
              {
                  for (int i = 0; i < DataSize; ++i) {
                      freeBytes.acquire();
                      buffer[i % BufferSize] = "ACGT"[QRandomGenerator::global()->bounded(4)];
                      usedBytes.release();
                  }
              }
          };

    消费者线程:

        class Consumer : public QThread
          {
              Q_OBJECT
          public:
              void run() override
              {
                  for (int i = 0; i < DataSize; ++i) {
                      usedBytes.acquire();
                      fprintf(stderr, "%c", buffer[i % BufferSize]);
                      freeBytes.release();
                  }
                  fprintf(stderr, "\n");
              }
          };

    这个示例展示了生产者要产生10万个数据,并循环放进8192大小的缓存区中,消费者同时去取缓存区数据。在生产者放的过程中,只能放置到未使用的空间或经过消费者处理过的空间中。

    信号量的引入保证了数据的读写的效率,也保证了消费者能够完整的拿到所有数据。而此例如果用互斥锁或读写锁实现的话效率将大打折扣(生产者:上锁(等待)----写满缓冲区-----解锁   消费者:上锁(等待)-----读缓冲区-----解锁),针对一个有多个字节的数据缓冲区读写不能同时进行。而使用信号量一边写未被写过的或已经被处理过的空间,一边将已写过的空间交给读进程操作将使程序效率大大提高。
     

    展开全文
  • QThread

    2019-06-16 11:09:25
    QThread类提供一种独立于平台的线程管理方式。翻译自官方文档(译者:Qt君)

    QThread类提供一种独立于平台的线程管理方式。

    头文件 #include <QThread>
    qmake QT += core
    继承于 QObject

    1.公有类型

    enum Priority { IdlePriority, LowestPriority, LowPriority, NormalPriority, …, InheritPriority}

    2.公有函数

    QThread(QObject *parent = nullptr)
    virtual ~QThread()
    QAbstractEventDispatcher * eventDispatcher() const
    void exit(int returnCode = 0)
    bool isFinished() const
    bool isInterruptionRequested() const
    bool isRunning() const
    int loopLevel() const
    QThread::Priority priority() const
    void requestInterruption()
    void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
    void setPriority(QThread::Priority priority)
    void setStackSize(uint stackSize)
    uint stackSize() const
    bool wait(unsigned long time = ULONG_MAX)

    3.公有重载函数

    virtual bool event(QEvent *event) override

    4.公有槽函数

    void quit()
    void start(QThread::Priority priority = InheritPriority)
    void terminate()

    5.信号

    void finished()
    void started()

    6.静态公有成员

    QThread * create(Function &&f, Args &&… args)
    QThread * create(Function &&f)
    QThread * currentThread()
    Qt::HANDLE currentThreadId()
    int idealThreadCount()
    void msleep(unsigned long msecs)
    void sleep(unsigned long secs)
    const QMetaObject staticMetaObject
    void usleep(unsigned long usecs)
    void yieldCurrentThread()

    7.受保护函数

    int exec()
    virtual void run()

    8.静态受保护成员

    void setTerminationEnabled(bool enabled = true)

    9.详细描述

      QThread类提供一种独立于平台的线程管理方式。
      一个QThread实例管理程序中的一个线程。QThread的执行开始于run()。默认情况下,run()通过调用exec()启动事件循环,并在线程内运行Qt事件循环。

    9.1使用QThread方法

    方法1(工作对象方法)

      你可以使用QObject::moveToThread()将工作对象移动到线程中使用。

    • 示例:
    class Worker : public QObject
    {
        Q_OBJECT
    public slots:
        void doWork(const QString &parameter) {
            QString result;
            /* ... here is the expensive or blocking operation ... */
            emit resultReady(result);
        }
    
    signals:
        void resultReady(const QString &result);
    };
    
    class Controller : public QObject
    {
        Q_OBJECT
        QThread workerThread;
    public:
        Controller() {
            Worker *worker = new Worker;
            worker->moveToThread(&workerThread);
            connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
            connect(this, &Controller::operate, worker, &Worker::doWork);
            connect(worker, &Worker::resultReady, this, &Controller::handleResults);
            workerThread.start();
        }
        
        ~Controller() {
            workerThread.quit();
            workerThread.wait();
        }
        
    public slots:
        void handleResults(const QString &);
        
    signals:
        void operate(const QString &);
    };
    

      将线程移动到工作线程内执行。因为在线程中有队列的信号槽连接机制,所以在不同线程中使用信号槽是安全的。

    方法2(继承QThread方法)

      另一种单独在线程中执行的方式是继承QThread后重新实现run()函数(run函数内用户的执行操作)。

    • 示例:
    class WorkerThread : public QThread
    {
        Q_OBJECT
        void run() override {
            QString result;
            /* ... here is the expensive or blocking operation ... */
            emit resultReady(result);
        }
    signals:
        void resultReady(const QString &s);
    };
    
    void MyObject::startWorkInAThread()
    {
        WorkerThread *workerThread = new WorkerThread(this);
        connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
        connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
        workerThread->start();
    }
    

      在上面示例中,线程将在运行函数返回后退出。除非调用exec(),否则线程中不会运行任何事件循环。

      重要的是要记住,QThread实例位于实例化它的旧线程中,而不是位于调用run()的新线程中。这意味着QThread的所有队列槽和调用的方法都将在旧线程中执行。因此,希望调用新线程中的槽的开发人员必须使用工作对象方法;新的槽不应直接实现到子类QThread中。

      与队列槽或调用的方法不同,直接在QThread对象上调用的方法将在调用该方法的线程中执行。当子类化QThread时,请记住构造函数在旧线程中执行,而run()在新线程中执行。如果从两个函数访问一个成员变量,则从两个不同的线程访问该变量。需要检查这样做是否安全。

      注意:在跨不同线程与对象交互时必须小心。有关详细信息,请参见同步线程。

    9.2管理线程

      QThread会通过信号started()finished通知你,或者您可以使用isFinished()isRunning()查询线程的状态。

      你可以调用exit()quit()来停止线程。在极端的情况下,你希望强制使用terminate()来终止线程。但是,这样做是又危险又令人气馁。详细请读terminate()setTerminateEnabled()相关文档。

      从Qt4.8起,通过将finished()信号连接到QObject::deleteLater(),可以释放位于刚刚结束的线程中的对象。

      使用wait()来阻塞调用线程,直到另外一个线程执行完成或直到经过指定时间。

      QThread还提供了与平台无关的静态睡眠函数:sleep()msleep()usleep()分别为秒、毫秒和微秒。这些函数在Qt 5.0中是公有函数(Qt 4.0版本为保护函数)。

      注意:wait()和sleep()函数通常是不必要的,因为Qt是一个事件驱动框架。与其使用wait(),还不如考虑监听finished()信号,或使用QTimer代替sleep()函数。

      静态函数currentThreadID()currentThread()返回当前执行线程的标识符。前者返回线程的平台特定ID;后者返回QThread指针。

      要选择线程的名称(例如,在Linux上的命令ps -L标识),可以在启动线程之前调用setObjectName()。如果不调用setObjectName(),则给线程的名称将是线程对象运行时类型的类名(例如,对于Mandelbrot示例中的"RenderThread",因为它是QThread子类的名称)。请注意,目前在Windows的发布版本中不可用。

      另外请参阅,Qt在线程中的支持, QThreadStorage, 同步线程, Mandelbrot示例, 信号量示例, 等待条件示例.

    10.成员类型文档

      枚举 QThread::Priority(优先权)
      此枚举类型指示操作系统应如何调度新创建的线程。

    常量 描述
    QThread::IdlePriority 0 仅在没有其他线程运行时调度。
    QThread::LowestPriority 1 调度的次数比LowPriority少。
    QThread::LowPriority 2 调度的次数比NormalPriority少。
    QThread::NormalPriority 3 操作系统的默认优先级。
    QThread::HighPriority 4 调度的次数比NormalPriority多。
    QThread::HighestPriority 5 调度的次数比HighPriority多。
    QThread::TimeCriticalPriority 6 经可能多地调度。
    QThread::InheritPriority 7 使用与创建线程相同的优先级。(这是默认值)

    11.成员函数文档

    QThread::QThread(QObject *parent = nullptr)
    

      构造一个新QThread来管理一个新线程。父线程拥有QThread的所有权。直到调用start(),线程才开始执行。
      另外请参阅start()


    [virtual] QThread::~QThread()
    

      销毁QThread。
      注意,删除QThread对象不会停止它管理的线程的执行。删除正在运行的QThread(即isFinished()返回false)将导致程序崩溃。在删除QThread之前,等待finished()信号。


    [static] QThread *QThread::create(Function &&f, Args &&... args)
    

      创建一个新的QThread对象,该对象将使用参数args和执行函数f。
      新线程没有启动,它必须通过显式调用start()启动。这允许您连接到它的信号,将QObjects移动到线程,选择新线程的优先级等等。函数f将在新线程中调用。
      返回新创建的QThread实例。

      注意:调用者获得返回的QThread实例的所有权。
      注意:此函数仅在使用c++ 17时可用。
      警告:不要多次调用返回的QThread实例上的start(),这样做会导致未定义的行为。

      该函数从Qt 5.10中引入。
      另外请参阅start()


    static] QThread *QThread::create(Function &&f)
    

      创建一个新的QThread对象,该对象将执行函数f。
      新线程没有启动,它必须通过显式调用start()启动。这允许您连接到它的信号,将QObjects移动到线程,选择新线程的优先级等等。函数f将在新线程中调用。
      返回新创建的QThread实例。

      注意:调用者获得返回的QThread实例的所有权。
      注意:此函数仅在使用c++ 17时可用。
      警告:不要多次调用返回的QThread实例上的start(),这样做会导致未定义的行为。

      该函数从Qt 5.10中引入。
      另外请参阅start()


    [static] QThread *QThread::currentThread()
    

      返回一个指向管理当前执行线程的QThread的指针。


    [static] Qt::HANDLE QThread::currentThreadId()
    

      返回当前执行线程的线程句柄。
      注意:在Windows上,这个函数返回由Win32函数GetCurrentThreadId()返回的DWORD(Windows线程ID),而不是由Win32函数GetCurrentThread()返回的伪句柄(Windows线程句柄)。
      警告:此函数返回的句柄用于内部目的,不应在任何应用程序代码中使用。


    [override virtual] bool QThread::event(QEvent *event)
    

      重新实现QObject::event()


    QAbstractEventDispatcher *QThread::eventDispatcher() const
    

      返回指向线程的事件调度程序对象的指针。如果线程不存在事件调度程序,则此函数返回0。
      该函数从Qt 5.0中引入。
      另外请参阅setEventDispatcher()


    [protected] int QThread::exec()
    

      进入事件循环,并等待直到调用exit(),返回传递给exit()的值。如果通过quit()调用exit(),返回的值为0。
      这个函数应该在run()中调用。需要调用这个函数(run())来启动事件处理。
      另外请参阅quit()exit()


    void QThread::exit(int returnCode = 0)
    

      告诉线程的事件循环使用退出代码退出。
      调用此函数后,线程离开事件循环,并从对QEventLoop::exec()的调用返回。QEventLoop::exec()函数返回退出代码
      按照惯例,退出代码为0表示成功,任何非零值表示错误。

      请注意,与同名的C库函数不同,此函数会返回到调用者和停止的事件处理。
      调用exit函数后在此线程中不再启动QEventLoop,直到再次调用QThread::exec()。 如果QThread::exec()中的事件循环没有运行,那么下一次调用QThread::exec()也会立即返回。
      另外请参阅quitQEventLoop


    [signal] void QThread::finished()
    

      该信号在完成执行之前从关联线程中发出。
      发出此信号时,事件循环已停止运行。 除延迟删除事件外,线程中不再处理任何事件。 此信号可以连接到QObject::deleteLater(),以释放该线程中的对象。

      注意:如果使用terminate()终止关联的线程,则不确定从哪个线程发出此信号。
      注意:这是一个私有信号。它可以用于信号连接,但不能由用户发出。
      另外请参阅started()


    [static] int QThread::idealThreadCount()
    

      返回可在系统上运行的理想线程数。这样就可以查询系统中的实际和逻辑处理器内核的数量。如果无法检测到处理器核心数,则此函数返回1。


    bool QThread::isFinished() const
    

      如果线程结束则返回true,否则返回false
      另外请参阅isRunning


    bool QThread::isInterruptionRequested() const
    

      如果可以停止在此线程上运行的任务,则返回true。requestInterruption()函数可以进行请求中断操作。

      此函数可用于长时间运行的任务中判断中断状态。 从不检查或操作此函数的返回值是安全的,但建议在长时间运行的函数中定期执行此操作。
      注意:不要经常调用它,以保持低开销。

    void long_task() {
         forever {
            if ( QThread::currentThread()->isInterruptionRequested() ) {
                return;
            }
        }
    }
    

    译者注:

    virtual void run() Q_DECL_OVERRIDE {
    	while (!isInterruptionRequested()) // 判断是否请求终止
    	{
    		/* 用户耗时操作 */
    	}
    }
    

      该函数从Qt 5.2中引入。
      另外请参阅currentThread()requestInterruption()


    bool QThread::isRunning() const
    

      如果线程正在运行则返回true,否则返回false
      另外请参阅isFinished()


    int QThread::loopLevel() const
    

      返回线程的当前事件循环级别。
      注意:这只能在线程本身内调用,即当它是当前线程时。
      该函数从Qt 5.5引入。


    [static] void QThread::msleep(unsigned long msecs)
    

      强制当前线程休眠msecs毫秒。

      如果您需要等待给定条件进行更改,请避免使用此功能。 相反,你应该将一个槽连接到指示更改的信号或使用事件处理程序(请参阅QObject::event())。

      注意:此功能不保证准确性。 在重负载条件下,应用程序可能比msecs睡眠时间更长。 某些操作系统可能会将msecs舍入到10 ms或15 ms。
      另外请参阅sleep()usleep


    QThread::Priority QThread::priority() const
    

      返回正在运行的线程的优先级。 如果线程未运行,则此函数返回InheritPriority
      该函数从Qt 4.1中引入。
      另外请参阅PrioritysetPriority()start()


    [slot] void QThread::quit()
    

      告诉线程的事件循环退出并返回代码0(成功)。相当于调用QThread::exit(0)
      如果线程没有事件循环,则此函数不执行任何操作。
      另外请参阅exit()QEventLoop


    void QThread::requestInterruption()
    

      请求中断线程。 该请求是建议性的,由线程上运行的代码来决定它是否以及如何根据此类请求执行操作。此函数不会停止在线程上运行的任何事件循环,也不会以任何方式终止它。

    译者注:
    示例:

    • 当用户执行killAndWait()函数后则会导致run()函数内循环体结束,从而结束线程执行。
    class WorkerThread : public QThread
    {
       Q_OBJECT
    public:
       void killAndWait()
       {
           requestInterruption(); /* 请求终止 */
           quit();
           wait();
       }
    
    protected:
       virtual void run() Q_DECL_OVERRIDE
       {
           while (!isInterruptionRequested()) /* 判断是否终止 */
           {
               /* 用户耗时操作 */
           }
       }
    };
    

      该函数从Qt 5.2中引入。
      另外请参阅isInterruptionRequested()


    [virtual protected] void QThread::run()
    

      线程的起点。在调用start()之后,新创建的线程自动调用此函数。默认实现只是调用exec()
      您可以重新实现此功能以便于高级线程管理。 从此方法返回将结束线程的执行。

      另外请参阅start()wait()


    void QThread::setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
    

      将线程的事件调度器设置为eventDispatcher。 只有当没有为该线程安装事件调度器时,才可以执行此操作。 也就是说,在使用start()启动线程之前,或者在主线程的情况下,在实例化QCoreApplication之前。 此方法获取对象的所有权。

      该函数从Qt 5.0中引入。
      另外请参阅eventDispatcher()


    void QThread::setPriority(QThread::Priority priority)
    

      此函数设置正在运行的线程的优先级。 如果线程没有运行,则此函数不执行任何操作并立即返回。使用start()启动具有特定优先级的线程。
      优先级参数可以是QThread::Priority枚举中的任何值,但InheritPriorty除外。
      优先级参数的影响取决于操作系统的调度策略。 特别是,在不支持线程优先级的系统上将忽略优先级(例如在Linux上,请参阅http://linux.die.net/man/2/sched_setscheduler以获取更多详细信息)。

      该函数从Qt 4.1中引入。
      另外请参阅Prioritypriority()start()


    void QThread::setStackSize(uint stackSize)
    

      将线程的最大堆栈大小设置为stackSize。如果stackSize大于0,则最大堆栈大小设置为stackSize字节,否则最大堆栈大小由操作系统自动确定。

      警告:大多数操作系统对线程堆栈大小设置了最小和最大限制。如果堆栈大小超出这些限制,则线程将无法启动。
      另外请参阅stackSize();


    [static protected] void QThread::setTerminationEnabled(bool enabled = true)
    

      根据enabled参数启用或禁用当前线程的终止。该线程必须由QThread启动。

      如果enabledfalse,则禁用终止。对QThread::terminate()的未来调用将立即返回而不起作用。相反,终止延迟直到启用终止。

      如果enabledtrue,则启用终止。对QThread::terminate()的未来调用将正常终止该线程。 如果终止已被延迟(即在终止禁用的情况下调用QThread::terminate()),则此函数将立即终止调用线程。 请注意,在这种情况下,此函数不会返回。

      另外请参阅terminate()


    [static] void QThread::sleep(unsigned long secs)
    

      强制当前线程休眠secs秒。

      如果您需要等待给定条件进行更改,请避免使用此功能。 相反,你应该将一个槽连接到指示更改的信号或使用事件处理程序(请参阅QObject::event())。

      注意:此功能不保证准确性。 在重负载条件下,应用程序可能会睡眠时间更长。
      另外请参阅msleep()usleep()


    uint QThread::stackSize() const
    

      返回线程的最大堆栈大小(如果使用setStackSize()设置),否则返回0。
      另外请参阅setStackSize()


    [slot] void QThread::start(QThread::Priority priority = InheritPriority)
    

      通过调用run()开始执行该线程。操作系统将根据优先级参数调度线程。如果线程已在运行,则此函数不执行任何操作。

      优先级参数的影响取决于操作系统的调度策略。特别是,在不支持线程优先级的系统上将忽略优先级(例如在Linux上,请参阅sched_setscheduler文档以获取更多详细信息)。

      另外请参阅run()terminate()


    [signal] void QThread::started()
    

      在调用run()函数之前,该信号在开始执行时从关联的线程发出。

      注意:这是一个私有信号。 它可以用于信号连接,但不能由用户发出。
      另外请参阅finished()


    [slot] void QThread::terminate()
    

      终止线程的执行。根据操作系统的调度策略,线程可能会立即终止也可能不会立即终止。 请确保terminate()之后使用QThread :: wait()来等待结束。

      当线程终止时,所有等待线程都将被唤醒。

      警告:此功能很危险不鼓励使用。线程可以在其代码路径中的任何位置终止。修改数据时可以终止线程。会导致线程无法自行清理,解锁任何保持的互斥锁等。简而言之,只有在绝对必要的情况下才使用此功能。

      可以通过调用QThread::setTerminationEnabled()显式启用或禁用terminate()的生效。在终止被禁用时调用此函数会导致终止延迟,直到重新启用终止。有关更多信息,请参阅QThread::setTerminationEnabled()的文档。
      另外请参阅setTerminationEnabled()


    [static] void QThread::usleep(unsigned long usecs)
    

      强制当前线程休眠usecs秒。

      如果您需要等待给定条件进行更改,请避免使用此功能。 相反,你应该将一个槽连接到指示更改的信号或使用事件处理程序(请参阅QObject::event())。

      注意:此功能不保证准确性。 在重负载条件下,应用程序可能会睡眠时间更长。一些操作系统可能将usecs调到10 ms或15 ms;另外在Windows上,它将调到1ms的倍数。
      另外请参阅sleep()usleep()


    bool QThread::wait(unsigned long time = ULONG_MAX)
    

      阻塞线程,直到满足以下任一条件

    • 条件1:与此QThread对象关联的线程已完成执行(即从run()返回时)。如果线程已完成,此函数将返回true。 如果线程尚未启动,它也会返回true。
    • 条件2:等待的时间已过。 如果时间是ULONG_MAX(默认值),那么等待将永远不会超时(线程必须从run()返回)。 如果等待超时,此函数将返回false。

      这提供了与POSIX pthread_join()函数类似的功能。
      另外请参阅sleep()terminate()


    [static] void QThread::yieldCurrentThread()
    

      如果有的话,将当前线程的执行产生到另一个可运行的线程。请注意,操作系统决定切换到那个线程。

    译者注: 放弃当前时间片切换到其他线程,而切换到那一个线程由系统决定。


    • 原文来源:
    https://doc.qt.io/qt-5/qthread.html
    
    • 译者:Qt君(微信公众号)
    展开全文
  • QThread使用

    2020-12-11 18:26:51
    QThread使用的两种方式moveToThreadsubclass QThreadQthread同步优雅的取消线程 QThread使用的两种方式   Qt提供了两种线程的使用方式,分别如下: moveToThread class Worker : public QObject { Q_OBJECT ...
  • QThread的用法

    万次阅读 多人点赞 2016-08-06 19:08:03
    概述 QThread类提供了一个与平台无关的管理线程的方法。一个QThread对象管理一个线程。QThread的执行从run()函数的执行开始,在Qt自带的QThread类中,run()函数通过调用exec()函数来启动事件循环机制,并且在线程...
  • Qt QThread

    2018-11-20 15:51:01
    QThread类提供了与平台无关的线程。 QThread从run()函数运行。run()通过调用exec()来开启事件循环,并在线程内运行一个Qt事件循环。 要创建一个线程,需要子类化QThread,并且重新实现run()函数。 #ifndef ...
  • Issue with QThread

    2021-01-09 09:15:07
    The program works fine at the beginning until I start using QThread. It seems to be freezing the UI, but the thread continues to run. UI will be responsive once the thread finishes. My assumption ...
  • QThread Qt

    2018-03-23 10:35:01
    QThread Qt函数moveToThread()函数原型:void QObject::moveToThread(QThread *targetThread);该函数用来改变对象的线程依附性,及该对象所属的线程,改变线程后,该对象的事件循环将在目标线程继续运行(对象收到的...
  • QThread Class

    2017-03-10 12:55:00
    TheQThreadclass provides a platform-independent way to manage threads. ps:QThread类提供了一种与平台无关的方式来管理线程。 AQThreadobject manages one thread of control within the program. QThreads ...
  • QThread详解

    2018-10-09 10:11:00
    回顾Qt之线程(QThread),里面讲解了如何使用线程,但还有很多人留言没有看明白,那么今天我们来一起瞅瞅关于QThread管理线程的那些事儿。。。 一、线程管理 1、线程启动 voidstart(Priority priority = ...
  • Qt 之 QThread(深入理解)

    万次阅读 多人点赞 2016-08-11 21:11:59
    简述前面,我们介绍了QThread常用的两种方式: worker-object 子类化QThread 下面,我们首先来看看子类化QThread在日常中的应用。简述 子类化QThread 在主线程中更新UI 正常结束线程 更多参考一般情况下,QThread...
  • Qt 之 QThread

    万次阅读 2016-07-01 13:14:51
    简述QThread类提供了与系统无关的线程。QThread代表在程序中一个单独的线程控制。线程在run()中开始执行,默认情况下,run()通过调用exec()启动事件循环并在线程里运行一个Qt的事件循环。 简述 详细描述 线程管理 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,761
精华内容 1,504
关键字:

qthread