zoukankan      html  css  js  c++  java
  • Qt新建线程

    方式一、创建一个类继承QThread

    启动一个线程的步骤:
    (1)  创建一个自己的线程类继承QT中的QThread类   创建线程类ThreadTest;
    (2)   在自己的ThreakTest类中重新实现run()函数, 该函数是一个死循环, 主要是完成自己需要的功能代码(但是一般会有一个条件while(condition){ ...... },来控制,否则线程怎么关闭)
    (3)  使用自己的类WorkThread 实例一个对象,也就是用该类创建一个变量 如: ThreadTest *test = new ThreadTest (this);
    (4)  然后通过start()函数启动这个线程, 如test->start();启动该线程
    重载的run()函数就是一个独立运行线程, 要想实现多线程就多次继承QThread类在不同的类中的run()函数中实现不同的功能

    (5) 通过控制condition使得这个条件为false停止死循环,然后调用test->quit()和test->wait()回收线程资源

    以下内容原文:http://blog.csdn.net/hai200501019/article/details/9899207

    方式二、继承QRunnable

    Qrunnable是所有可执行对象的基类。我们可以继承Qrunnable,并重写虚函数void QRunnable::run () 。我们可以用QThreadPool让我们的一个QRunnable对象在另外的线程中运行,如果autoDelete()返回true(默认),那么QThreadPool将会在run()运行结束后自动删除Qrunnable对象。可以调用void QRunnable::setAutoDelete ( bool autoDelete )更改auto-deletion标记。需要注意的是,必须在调用QThreadPool::start()之前设置,在调用QThreadPool::start()之后设置的结果是未定义的。

    下面是我写的简单的例子:

    class Runnable:publicQRunnable
    {
           //Q_OBJECT   注意了,Qrunnable不是QObject的子类。
    public:
           Runnable();
           ~Runnable();
           voidrun();
    protected:
    private:
    };
    Runnable::Runnable():QRunnable()
    {
    
    }
    
    Runnable::~Runnable()
    {
           cout<<"~Runnable()"<<endl;
    }
    
    void Runnable::run()
    {
           cout<<"Runnable::run()thread :"<<QThread::currentThreadId()<<endl;
           cout<<"dosomething ...."<<endl;
    }
    
    int main(int argc, char *argv[])
    {
           QCoreApplication a(argc, argv);
    
           cout<<"mainthread :"<<QThread::currentThreadId()<<endl;
    
           Runnable runObj;
    
           QThreadPool::globalInstance()->start(&runObj);
    
           returna.exec();
    
    }

    由结果可看出,run()确实是在不同于主线程的另外线程中运行的,而且在运行结束后就调用了析构函数,因为默认是可以自动被销毁的。

    我们可以对同一个对象多次调用QThreadPool::start(),如果是可以自动被销毁的,Qrunnable对象会在最后一个线程离开了run函数之后才被销毁的。

    int main(int argc, char *argv[])
    {
    
           QCoreApplication a(argc, argv);
    
           cout<<"mainthread :"<<QThread::currentThreadId()<<endl;
    
           Runnable runObj;
    
           QThreadPool::globalInstance()->start(&runObj);
    
           QThreadPool::globalInstance()->start(&runObj);
    
           QThreadPool::globalInstance()->start(&runObj);      
    
           returna.exec();
    
    }

    我三次调用QThreadPool::globalInstance()->start(&runObj);,但是在三次都执行完之后才运行析构函数。

    这种新建线程的方法的最大的缺点就是:不能使用Qt的信号—槽机制,因为Qrunnable不是继承自QObject。所以我们要想知道线程是否运行结束或获取运行结果可能会比较麻烦。还有就是我们不能直接调用run()启动线程,必须借助于QthreadPool。

    但是这种方法的好处就是,可以让QThreadPool来管理线程,QThreadPool会自动的清理我们新建的Qrunnable对象。

    方式三、使用moveToThread 

    首先我们必须实现继承QObject的一个类,实现我们想要的功能。

    class Worker:publicQObject
    {
           Q_OBJECT
    public:
           Worker();
           ~Worker();
    protected slots:
    
           voidfun1();
    
       void fun2();
    
    private:
    
    };
    Worker::Worker():QObject()
    
    {        }
    Worker::~Worker()
    
    {     }
    
    void Worker::fun1()
    {
           cout<<"Worker::fun1()  thread : "<<QThread::currentThreadId()<<endl;
    }

    接着创建一个对象,并调用:moveToThread ( QThread * targetThread ),让对象在新的线程中运行。

    int main(int argc, char *argv[])
    {
           QCoreApplication a(argc, argv);
    
           cout<<"mainthread :"<<QThread::currentThreadId()<<endl;
    
           QThread thread;
    
           Worker work;
    
           thread.start();              //注意记得启动线程
    
           work.moveToThread(&thread);
    
    //由于不能直接调用worker
    
    //的函数,所以一般用信号触发调用
    
    QTimer::singleShot(0,&work,SLOT(fun1()));  
    
    QTimer::singleShot(0,&work,SLOT(fun1()));  
    
           returna.exec();
    }

    这样就能让fun1()和fun2()都运行在thread线程中了。

     

    需要注意的是:在work 的函数结束运行前,thread不能被析构。Thread的生命期不能小于work。否则的话程序就好崩掉了。

    像下面的代码肯定是不行的。

    void Dialog::startWork()
    {
    
           QThread thread;
    
          Worker*work = new Worker;
    
           thread.start();
    
           work->moveToThread(&thread);
    
           QTimer::singleShot(0,work,SLOT(fun1()));
    
           QTimer::singleShot(0,work,SLOT(fun2()));
    
    }

    所以thread 必须是new出来的。但是这样的话,就感觉有点麻烦,我们要同时管理thread和work,因为都是new 出来,我们需要负责清理。为了避免这样的麻烦,我想到的方法是,在work类中添加一个QThread成员。

    class Worker:publicQObject
    {
           Q_OBJECT
    public:
           Worker();
           ~Worker();
    protected slots:
                  voidfun1();
                  voidfun2();
    private:
           QThread m_thread;
    };
    
    Worker::Worker():QObject()
    {
           m_thread.start();
           this->moveToThread(&m_thread);
    }

    这样我们在用的时候只需要newwork就行了。

    方法四、使用QtConcurrent::run

    其实前面也有用到QtConcurrent::run启动新线程了。QtConcurrent命名空间提供了很多方法可以实现并发编程,这个以后再深入探讨了,这里只是大概讲一下启动线程。还是用上面的worker代码作为例子:

    void Worker::start()
    {
           QtConcurrent::run(this,&Worker::fun1);
    
           QtConcurrent::run(this,&Worker::fun2);
    }
    
    //QtConcurrent::run是个模板函数,有很多种形式,我们也可以让全局的函数允许在另外的线程中。
    
    void printMes(char*mes)
    {
           cout<<"pprintMes(char*mes)  thread : "<<QThread::currentThreadId()<<endl;
    
           cout<<mes<<endl;
    }
    
    int main(int argc, char *argv[])
    {
           QCoreApplication a(argc, argv);
    
           cout<<"mainthread :"<<QThread::currentThreadId()<<endl;
    
           char *mes= "hello world";
    
           QtConcurrent::run(printMes,mes);
    
           returna.exec();
    }
  • 相关阅读:
    鸟哥私房菜*基础篇(3)
    Java 基于Graphics2D绘制电子收据图片
    微信扫码支付沙盒测试,解决沙盒环境下签名验证失败
    JAVA对象合集,根据条件过滤
    java对象根据字段进行排序
    vue 弹窗调用父窗口函数
    php使用post功能,调用微信推送服务
    JS字符串截取
    关于两个 IQueryable 合并
    bootstrap清除数据源
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/15090150.html
Copyright © 2011-2022 走看看