• Qt中的多线程编程


    Qt中的多线程编程

     

     

     QThread编程示例

    复制代码
    class MyThread: public QThread   //创建线程类
    {
    protected:
        void run()   //线程入口函数
        {
            for(int i=0; i<5; i++)
            {
                qDebug() << objectName() << ":" << i;
                sleep(1)  //暂停1s
            }
        }
    
    };
    复制代码

    多线程编程初探

    实例1:

    复制代码
    #include <QCoreApplication>
    #include <QThread>
    #include <QDebug>
    
    class MyThread : public QThread
    {
    protected:
        void run()
        {
            qDebug() << objectName() << " : " << "run() begin";
            for(int i=0; i<5; i++)
            {
                qDebug() << objectName() << ": " << i;
                sleep(1);
            }
            qDebug() << objectName() << " : " << "run() end";
        }
    
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        qDebug() << "main() begin";
    
        MyThread t;
        t.setObjectName("t");
        t.start();   //创建一个线程,并执行线程体run函数
    
        qDebug() << "main() end";
    
        return a.exec();
    }
    复制代码

     

    示例中的主线程将先于子线程结束,所有线程都结束后,进程结束

     实例2

    复制代码
    #include <QCoreApplication>
    #include <QThread>
    #include <QDebug>
    
    class MyThread : public QThread
    {
    protected:
        void run()
        {
            qDebug() << objectName() << " : " << "run() begin";
            for(int i=0; i<5; i++)
            {
                qDebug() << objectName() << ": " << i;
                sleep(1);
            }
            qDebug() << objectName() << " : " << "run() end";
        }
    
    
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        qDebug() << "main() begin";
    
        MyThread t;
        t.setObjectName("t");
        t.start();   //创建一个线程,并执行线程体run函数
    
        MyThread tt;
        tt.setObjectName("tt");
        tt.start();
    
        for(int i=0; i<100000; i++)
        {
            for(int j=0; j<10000; j++)
            {
    
            }
        }
    
    
        qDebug() << "main() end";
    
        return a.exec();
    }
    复制代码

    第一次运行结果:

     第二次运行结果

     从上面的运行结果看,每次运行结果都不同。

    在主线程中创建的两个子线程是并行执行的,这两个线程间没有交互,各自执行。这就是线程间的并行性

     重要注意:

    在工程开发中terminate是禁止使用的,terminate会使得操作系统暴力终止线程,而不考虑数据的完整性、资源释放等问题。

    问题:如何在代码中优雅的终止线程

    解决方案思路:

    -run函数执行结束是优雅终止线程的唯一方式

    -在线程类中增加标识变量m_toStop(volatile bool)每次都需要从内存中读取,不需要编译器做任何的优化。

    -通过m_toStop的值判断是否需要从run函数返回

    复制代码
    class Solution : public QThread
    {
    protected:
        volatile bool m_toStop;
        void run();
    public:
        Solution()
        {
            m_toStop = false;
        }
        
        void stop()
        {
            m_toStop = true;
        }
    
    };
    
    void Solution::run()
    {
        while(!m_toStop)
        {
            //do task
        }
    }
    复制代码

    首先看一下暴力终止线程的例子:

    复制代码
    #include <QCoreApplication>
    #include <QThread>
    #include <QDebug>
    
    class MyThread : public QThread
    {
    protected:
        void run()
        {
            qDebug() << objectName() << " : " << "run() begin";
            for(int i=0; i<20; i++)
            {
                qDebug() << objectName() << ": " << i;
                msleep(500);
            }
            qDebug() << objectName() << " : " << "run() end";
        }
    
    
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        qDebug() << "main() begin";
    
        MyThread t;
        t.setObjectName("t");
        t.start();   //创建一个线程,并执行线程体run函数
    
        for(int i=0; i<100000; i++)
        {
            for(int j=0; j<10000; j++)
            {
    
            }
        }
    
        t.terminate();
        qDebug() << "main() end";
    
        return a.exec();
    }
    复制代码

     在子线程中需要执行20次的,但当使用了terminate()暴力终止线程时,该线程出现了非正常死亡,该种方式不安全,也不优雅。

    下面看一个暴力终止一个线程,带来内存泄露的问题。

    复制代码
    #include <QCoreApplication>
    #include <QThread>
    #include <QDebug>
    
    class MyThread : public QThread
    {
    protected:
        void run()
        {
            qDebug() << objectName() << " : " << "run() begin";
    
            int* p = new int[10000];
    
            for(int i=0; i<20; i++)
            {
                qDebug() << objectName() << ": " << i;
                msleep(500);
            }
    
            delete[] p;
            qDebug() << objectName() << " : " << "run() end";
        }
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        qDebug() << "main() begin";
    
        MyThread t;
        t.setObjectName("t");
        t.start();   //创建一个线程,并执行线程体run函数
    
        for(int i=0; i<100000; i++)
        {
            for(int j=0; j<10000; j++)
            {
    
            }
        }
    
        t.terminate();
        qDebug() << "main() end";
    
        return a.exec();
    }
    复制代码

    在子线程中,申请了一片堆空间,定义了10000个int型的数据。我们知道,堆空间只要申请了,就必须释放。但是上面这个程序释放了吗?看样子是真的释放了,但事实真的如此吗?看一下打印结果:

     从打印结果看,for循环只是运行了17次,就说明该子线程没有运行完,该线程就被暴力终止了。因此delete[] p肯定没有执行,申请了堆空间,没有被释放,那么将会产生内存泄露。

    下面来看一下优雅的结束线程

    复制代码
    #include <QCoreApplication>
    #include <QThread>
    #include <QDebug>
    
    class MyThread : public QThread
    {
    protected:
        volatile bool m_toStop;
    
        void run()
        {
            qDebug() << objectName() << " : " << "run() begin";
    
            int* p = new int[10000];
    
            for(int i=0; (!m_toStop)&&(i<20); i++)
            {
                qDebug() << objectName() << ": " << i;
                msleep(500);
            }
    
            delete[] p;
            qDebug() << objectName() << " : " << "run() end";
        }
    public:
        MyThread()
        {
            m_toStop = false;
        }
    
        void stop()
        {
            m_toStop = true;
        }
    
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        qDebug() << "main() begin";
    
        MyThread t;
        t.setObjectName("t");
        t.start();   //创建一个线程,并执行线程体run函数
    
        for(int i=0; i<100000; i++)
        {
            for(int j=0; j<10000; j++)
            {
    
            }
        }
    
        t.stop();
        qDebug() << "main() end";
    
        return a.exec();
    }
    复制代码

    使用t.stop优雅的结束线程,从打印结果看,t run() end被执行了,说明delete[] p被执行了,申请的堆空间被释放了。(注意,即使20次for循环没有被执行完,但是申请的堆空间被释放,达到了我们的要求)。

    这种解决方案并不只适用Qt开发中,在其他的平台开发中,只要涉及多线程都可以考虑这种解决方案。

  • 相关阅读:
    [Cypress] install, configure, and script Cypress for JavaScript web applications -- part4
    [Angular] Lazy Load CSS at runtime with the Angular CLI
    [置顶] 半年的工作总结
    分享4个未注册*sdn域名
    Windows 已在 DImageProcess.exe 中触发一个断点。
    Foundation: Binary Search
    HDU 3016 Man Down (线段树+dp)
    网络智能和大数据公开课Homework3 Map-Reduce编程
    centos 6.2 关闭 IPV6
    [置顶] 【Git入门之八】分支管理
  • 原文地址:https://www.cnblogs.com/bruce1992/p/14320451.html
Copyright © 2020-2023  润新知