• C++多线程


    C++11中支持内置的thread库,此库兼容window和linux,在不同的平台都可以编译

    实现线程并发

    一个进程中可以存在并运行多个线程,其中有一个是主线程,当主线程结束后这个进程就结束了,所以要实现线程的并发,就要在主线程结束之间进行

    创建线程的方法

    1. 传递一个普通函数
    #include 
    #include 
    #include 
    
    void func(const std::string &str) {
        for (int i = 0; i < 10; ++i) {
            std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
            Sleep(1000);
        }
        std::cout << str << "线程执行完毕" << std::endl;
    }
    
    int main() {
        std::cout << "主线程开始" << std::endl;
    
        std::thread t1(func, "t1");
        for (int i = 0; i < 10; i++) {
            std::cout << "主线程\n";
            Sleep(1000);
        }
        std::cout << "主线程结束" << std::endl;
        t1.join();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    1. 传递一个lambda函数
    #include 
    #include 
    #include 
    
    int main() {
        std::cout << "主线程开始" << std::endl;
        auto f = [](const std::string &str) {
            for (int i = 0; i < 10; ++i) {
                std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
                Sleep(1000);
            }
            std::cout << str << "线程执行完毕" << std::endl;
        };
        std::thread t2(f, "t2");
        for (int i = 0; i < 10; i++) {
            std::cout << "主线程\n";
            Sleep(1000);
        }
        std::cout << "主线程结束" << std::endl;
        t2.join();
        return 0;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    1. 传递一个仿函数
    #include 
    #include 
    #include 
    class MyThread {
    public:
    	// 仿函数的书写要重写其()运算符
        void operator()(const std::string &str) {
            for (int i = 0; i < 10; ++i) {
                std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
                Sleep(1000);
            }
            std::cout << str << "线程执行完毕" << std::endl;
        };
    };
    
    int main() {
        std::cout << "主线程开始" << std::endl;
        std::thread t3(MyThread(), "t3");
        for (int i = 0; i < 10; i++) {
            std::cout << "主线程\n";
            Sleep(1000);
        }
        std::cout << "主线程结束" << std::endl;
        t3.join();
        return 0;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    1. 传递一个类的静态成员函数
    #include 
    #include 
    #include 
    class Mythread2 {
    public:
        static void func(const std::string &str) {
            for (int i = 0; i < 10; ++i) {
                std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
                Sleep(1000);
            }
            std::cout << str << "线程执行完毕" << std::endl;
        }
    };
    
    int main() {
        std::cout << "主线程开始" << std::endl;
        std::thread t4(Mythread2::func, "t4");
        for (int i = 0; i < 10; i++) {
            std::cout << "主线程\n";
            Sleep(1000);
        }
        std::cout << "主线程结束" << std::endl;
        t4.join();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    1. 传递一个类的成员函数
    #include 
    #include 
    #include 
    class Mythread3 {
    public:
        void func(const std::string &str) {
            for (int i = 0; i < 10; ++i) {
                std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
                Sleep(1000);
            }
            std::cout << str << "线程执行完毕" << std::endl;
        }
    };
    
    int main() {
        std::cout << "主线程开始" << std::endl;
        Mythread3 thread3;
        std::thread t5(&Mythread3::func, &thread3, "t5");
        for (int i = 0; i < 10; i++) {
            std::cout << "主线程\n";
            Sleep(1000);
        }
        std::cout << "主线程结束" << std::endl;
        t5.join();
        return 0;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    thread.join

    上面创建线程如果不添加join,程序就有可能报错

    原因就是,主线程和子线程不能确定谁先执行完。两个线程无论是哪个先执行完毕都导致程序异常终止。
    因为主线程资源会在程序结束后被回收,而子线程不会被回收。
    对于多线程程序中的线程资源一定要被回收,不然就会报错

    线程执行join的作用是
    将线程加入到线程队列中之前,主线程要等待子线程执行完毕之后才会执行

    #include 
    #include
    using namespace std;
    
    
    
    void myPrint()
    {
        for(int i=0; i<10; i++)
        {
            cout << "线程正在执行" <<i<<endl;
        }
    }
    int main()
    {
    
        thread firstThread(myPrint);
        firstThread.join();
        for(int j =0;j<5;j++)
        {
            cout<<"主线程正在执行"<<j<<endl;
        }
        return 0;
    }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    输出结果:
    在这里插入图片描述

    • 如果去除了join方法,程序就会发生难以预测的错误
      在这里插入图片描述

    thread.detch()

    子线程可以脱离主线程,两者并发执行,当主线程执行完毕之后,子线程将会被移动到C++运行时库管理,也就时放到了后台执行,这样不会时程序发生错误,但是子程序执行的结果不会出现在控制台

    #include 
    #include
    using namespace std;
    
    
    
    void myPrint()
    {
        for(int i=0; i<10000; i++)
        {
            cout << "线程正在执行" <<i<<endl;
        }
    }
    int main()
    {
    
        thread firstThread(myPrint);
    //    firstThread.join();
        firstThread.detach();
        for(int j =0;j<5;j++)
        {
            cout<<"主线程正在执行"<<j<<endl;
        }
        return 0;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    执行结果:
    在这里插入图片描述

    • 在子线程执行到803次循环时,主线程就结束了,所以后面的循环在控制台没有输出,这并不代表程序会在这里中断,说不定下次就能执行1000多次循环,这是未知的。
    • (但是可以知道的是main函数中的循环结束后程序依然在执行,说明程序没有在此中断。
    • 最后也没有因为主线程的结束而出现程序的错误,说明detach确实将子线程移动到了后台运行。

    thread.joinable()

    判断子线程能否加入到线程队列中

    • 一般当线程执行join后不能再次执行join
    • 在线程执行detach后不能再次执行join
    #include 
    #include
    using namespace std;
    
    
    
    void myPrint()
    {
        for(int i=0; i<10; i++)
        {
            cout << "线程正在执行" <<i<<endl;
        }
    }
    int main()
    {
    
        thread firstThread(myPrint);
    
        if(firstThread.joinable())
        {
            cout<<"子线程可以join"<<endl;
            firstThread.join();
        }
        else
        {
            cout<<"子线程不能join"<<endl;
        }
        if(firstThread.joinable())
        {
            cout<<"子线程可以join"<<endl;
            firstThread.join();
        }
        else
        {
            cout<<"子线程不能join"<<endl;
        }
    //    firstThread.join();
    //    firstThread.detach();
        for(int j =0;j<5;j++)
        {
            cout<<"主线程正在执行"<<j<<endl;
        }
        return 0;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    执行结果:
    在这里插入图片描述

    pthread_cancle()

    在window下的thread中无法对其进行操作
    但在linux下的pthread库可以操作将子线程在主线程的运行状态下中断

    #include 
    #include 
    #include
    
    int main() {
        std::cout << "主线程开始" << std::endl;
        auto f = [](const std::string &str) {
            for (int i = 0; i < 10; ++i) {
                std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
                std::this_thread::sleep_for(std::chrono::seconds(5));
            }
            std::cout << str << "线程执行完毕" << std::endl;
        };
    	thread t5(f, "t5");
        std::this_thread::sleep_for(std::chrono::seconds(5));
        pthread_t thid = t5.native_handle();
        pthread_cancel(thid);
    	t5.join();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    因为子线程等待的时间是10秒,主线程等待的时间是5秒,按照常理子线程整个程序会等待10秒后停止执行
    主线程可以通过使用pthread_cancle来终止子线程的执行,要传递的是子线程的id(注意:这里的id不能通过get_id来获取,这里的id指的是pthread_id,只能通过native_handle()函数来获取

  • 相关阅读:
    iPhone设备中如何导出和分享应用程序崩溃日志的实用方法
    [微前端实战]---040 子应用接入微前端-react15,react17
    英伟达DeepStream学习笔记47——deepstream sdk安装
    java计算机毕业设计ssm物流快递管理系统
    快手,得物,蓝月亮,蓝禾,奇安信,三七互娱,顺丰,康冠科技,金证科技24春招内推
    信创办公–基于WPS的PPT最佳实践系列 (绘制自选图形)
    【可视化大屏学习2】大屏帧率、大屏设计(ui)等
    二维列表对应一维列表的内容子串查询,并返回下标
    net自动排课系统完整源码(适合智慧校园)
    青阳网络文件传输系统 kiftd 1.1.0 正式发布!
  • 原文地址:https://blog.csdn.net/m0_56104219/article/details/126895288