美文网首页
多线程学习(一)

多线程学习(一)

作者: lxr_ | 来源:发表于2021-11-09 09:59 被阅读0次

    //程序运行生成一个进程,该进程下的主线程main()函数开始自动运行
    //主线程main()开始执行,自己创建的线程也需要从一个函数开始运行(也被称为初始函数),此函数运行完毕,代表该线程运行结束
    //整个进程是否执行完毕的标志是 主线程main是否执行完毕,主线程main执行完毕,则进程执行完毕
    //一般情况下,如果主线程已经执行完毕,其他子线程(自己创建的)还没有执行完毕,那么其他子线程也会被操作系统强行终止
    //所以一般情况下,如果想保持子线程(自己创建的)运行状态,需要让主线程一直保持运行。但是有例外,后续说明

    #include "stdafx.h"
    #include <iostream>
    #include <thread>
    
    using namespace std;
    
    //自己创建的线程从此函数开始运行(初始函数)
    void myPrint()
    {
        cout << "我的线程开始执行..." << endl;
        //...
        //...
        cout << "我的线程执行完毕..." << endl;
    }
    
    //thread:是标准库中的类
    //join():阻塞并等待的作用,此处阻塞主线程,让主线程等待子线程执行完毕
    //然后子线程和主线程汇合,主线程继续执行
    int main(int argc, char** argv)
    {
        //创建线程步骤:
        //a)包含头文件thread
        //b)创建初始函数
        //c)main中开始实现
    
        thread myThread(myPrint);  //参数:可调用对象 (此处为一个函数myPrint)
        //该语句创建线程myThread 线程执行的入口为myPrint()函数,并开始执行
        //此时程序中有两个线程(main和myThread)在跑,整个程序有两条线同时走
        //即使一条线被堵住,另一条线可继续执行
        
        myThread.join();           //主线程阻塞到这里等待myPrint执行完             
                                   //当myPrint执行完,join执行完毕,主线程main继续执行       
    
        cout << "hello,world!" << endl;
    
        return 0;
    }
    

    执行结果如下图所示,由于join的阻塞和等待作用,所以显示结果为:子线程执行完后,主线程继续执行
    如果未加join函数,则程序运行时出错,分析:子线程还未执行完,但主线程已经执行完,子线程被强制退出,导致程序异常(这种程序不合格)
    一个良好的程序应该是主线程等待子线程执行完毕后,主线程才能退出

    执行结果

    //传统多线程程序在主线程中要等待子线程执行完毕,然后主线程退出
    //detach():分离,主线程不和子线程汇合,各自执行,主线程不等子线程运行结束,可以先运行结束
    //为什么引入detach():创建了很多子线程的情况下,让主线程逐个等待子线程结束,当这种编程方法不适合时,引入detach()
    //一旦detach()之后,与这个主线程关联的thread对象就会失去与主线程的关联,此时子线程就会驻留在后台运行,相当于被C++运行时库接管,当子线程执行完后,由运行时库负责清理线程资源

    void myPrint1()
    {
        cout << "我的线程开始执行..." << endl;
        //...
        //...
        cout << "我的线程执行完毕1..." << endl;
        cout << "我的线程执行完毕2..." << endl;
        cout << "我的线程执行完毕3..." << endl;
        cout << "我的线程执行完毕4..." << endl;
        cout << "我的线程执行完毕5..." << endl;
        cout << "我的线程执行完毕6..." << endl;
        cout << "我的线程执行完毕7..." << endl;
        cout << "我的线程执行完毕8..." << endl;
        cout << "我的线程执行完毕9..." << endl;
        cout << "我的线程执行完毕10..." << endl;
        cout << "我的线程执行完毕11..." << endl;
        cout << "我的线程执行完毕12..." << endl;
    }
    int main(int argc, char** argv)
    {
    
        thread myThread(myPrint1);  //创建线程并开始执行
    
        myThread.detach();         //子线程与主线程分离
        //myThread.join();         //detach()后,不能join,否则程序运行异常
    
        cout << "hello,world 1" << endl;
        cout << "hello,world 2" << endl;
        cout << "hello,world 3" << endl;
    
        return 0;
    }
    

    其中一种执行结果如下图所示,有多种执行结果,因为主线程和子线程互不影响,但是当主线程执行完毕后,进程就退出了,这时子线程会转移到后台执行,这里观察不到子线程后续执行结果
    detach后,子线程myPrint1失去自己的控制,并且一旦调用了detach(),就不能再用join()

    执行结果

    //joinable():判断现在是否可以使用join或者detach(),返回true(可以join或detach)或者false(不能使用join或detach)

    int main(int argc, char** argv)
    {
        thread myThread(myPrint);              //创建线程并开始执行
    
        if (myThread.joinable())               //可以join或者detach
        {
            cout << "before detach/join:" << endl;
            cout << "joinable()==true" << endl;
    
            myThread.join();                  //join操作,即阻塞主线程让主线程等待子线程执行完毕
        }
        else
        {
            cout << "before detach/join:" << endl;
            cout << "joinable()==false" << endl;
        }
    
        //执行完join或者detach后
        if (myThread.joinable())
        {
            cout << "after detach/join:" << endl;
    
            cout << "joinable()==true" << endl;
        }
        else
        {
            cout << "after detach/join:" << endl;
            cout << "joinable()==false" << endl;
        }
    
        cout << "hello,world" << endl;      //主线程操作
    
        return 0;
    }
    

    执行结果如下图所示,在join/detach之前,joinable函数返回结果为true,join操作后返回false


    执行结果

    //其他创建线程的方法:
    //创建线程时调用对象为函数对象

    class TA
    {
    public:
        void operator()()                  //重载()运算符,不能有参数
        {
            cout << "我的线程开始operator()开始执行..." << endl;
            cout << "我的线程operator()结束执行..." << endl;
        }
    };
    
    int main(int argc, char** argv)
    {
        TA ta;
        thread myThread(ta);              //函数对象ta为参数:可调用对象
    
        myThread.join();                  //等待子线程执行结束
    
        cout << "hello world" << endl;
     
        return 0;
    }
    

    执行结果如下图所示,正常执行

    执行结果
    //可能犯得一种bug如下:
    //************ 一个坑 ***************
    class TA1
    {
    public:
        int m_i;
        TA1(int& i):m_i(i)
        {
            cout << "TA1构造函数" << endl;
        }
        TA1(const TA1& ta):m_i(ta.m_i)
        {
            cout << "TA1拷贝构造函数" << endl;
        }
    
        ~TA1()
        {
            cout << "TA1析构函数" << endl;
        }
    
    
        void operator()()                  //重载()运算符,不能有参数
        {
            cout << "m_i1的值为:" << this->m_i << endl;
            cout << "m_i2的值为:" << this->m_i << endl;
            cout << "m_i3的值为:" << this->m_i << endl;
            cout << "m_i4的值为:" << this->m_i << endl;
            cout << "m_i5的值为:" << this->m_i << endl;
    
        }
    };
    
    int main(int argc, char** argv)
    {
        int i = 10;
        TA1 ta(i);                        //会调用有参构造
        thread myThread(ta);              //函数对象ta为参数:可调用对象  此处调用拷贝构造函数
    
        //myThread.detach();                  //子线程与主线程分离
        myThread.join();
    
        cout << "hello world" << endl;
    
        return 0;
    }
    

    //问题:产生不可预料的结果,因为主线程执行完后,i变量内存回收,子线程无法对i引用
    //解决:可以将detach改为join等待子线程,也可以将m_i定义为int类型,则可以直接将i的值copy过来

    //疑问:ta为局部变量,一旦调用了detach,若主线程先执行结束,子线程调用的这个ta还存在吗?(对象不存在)
    //解答:这个对象实际上是被复制到线程中的,所以执行完主线程后,ta会被销毁,但被复制的对象依旧存在

    //所以,只要TA类中没有引用、指针,就不会产生问题
    如下图所示,当使用detach时,由于主线程先执行完毕后,ta对象被析构,而子线程还未执行完毕,此时拷贝的对象还未被析构,故显示只执行了一次析构,其实子线程还在后台运行,执行结果如下图所示。

    执行结果
    如果使用join,由于主线程等待子线程执行完毕,则子线程完整执行,所以它的析构函数会执行
    image.png
    //创建线程时调用对象为lambda表达式
    int main(int argc, char** argv)
    {
        auto lam = [] {
            cout << "lambda表达式创建线程..." << endl;
            //....
            cout << "lambda thread执行结束..." << endl;
    
        };                        //lambda表达式
    
        thread lambdaThread(lam); //创建线程并开始执行
        lambdaThread.join();      //等待子线程执行完毕
    
        cout << "hello world" << endl;
    
        return 0;
    }
    

    执行结果如下图所示


    执行结果

    相关文章

      网友评论

          本文标题:多线程学习(一)

          本文链接:https://www.haomeiwen.com/subject/gvtpzltx.html