• C++多线程03 Lambda表达式与caII once


    一、Lambda表达式做为线程入口

    Lambda(匿名函数)表达式是C++11最重要的特性之一,lambda来源于函数式编程的概念,也是现代编程语言的一个特点。

    优点如下:

    声明式编程风格:就地匿名定义目标函数或函数对象,有更好的可读性和可维护性。
    简洁:不需要额外写一个命名函数或函数对象,,避免了代码膨胀和功能分散。
    更加灵活:在需要的时间和地点实现功能闭包。
    概念及基本用法
    lambda表达式定义了一个匿名函数,并且可以捕获一定范围内的变量。语法形式如下:

    [ capture ] ( params ) opt -> ret { body; };
    
    • 1

    1
    capture:捕获列表
    params:参数列表
    opt:函数选项
    ret:返回值类型
    body:函数体
    一个完整的lambda表达式是这样:

    auto f = [](int a) -> int {return a + 1;};
    cout << f(3) << endl;  //输出4
    
    • 1
    • 2

    详细版本原文链接:https://blog.csdn.net/luoyayun361/article/details/123491439

    直接定义一个线程对象:

    };
    int main(int argc, char* argv[])
    {
        thread th(
            [](int i) {cout << "test lmbda " << i << endl; },
            123
        );
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述
    [](int i) {cout << "test lmbda " << i << endl; 相当于函数指针,指向一个打印test lmbda i的函数,i的值由第二个参数先拷贝,再传给这个指针指向的函数

    用对象做为一个线程

    class TestLambda
    {
    public:
        void Start()
        {
            thread th([this]() {cout << "name = " << name << endl; });
            th.join();
        }
    
        string name = "test lambda";
    };
    int main(int argc, char* argv[])
    {
        TestLambda test;
        test.Start();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    先创建一个对象,该对象有一个成员name
    再调用该类的start方法,该方法将一个Lambda表达式包装成线程,并让该线程阻塞主线程,该Lambda表达式做为线程入口,捕获列表捕获了该对象的this指针,指明了打印哪个对象的name
    在这里插入图片描述

    二、caII once多线程函数调用,但函数只进入一次

    比如多个线程都要初始化一个库,但只需要进入一次,可以使用个全局变量来进行判断,一旦有一个线程对其初始化了便将其设为false,其他线程便进不去了,但这样效率偏低,并且影响代码可读性,于是使用一个新的方法:

    std::call_once():
    该函数的第一个参数为标记,第二个参数是一个函数名。
    功能:能够保证多线程调用函数func()时只被调用一次。具备互斥量的能力,而且比互斥量消耗的资源更少,更高效。
    call_once()需要与一个标记结合使用,这个标记为std::once_flag;其中once_flag是一个数据结构,call_once()就是通过标记来决定函数是否执行,调用成功后,就把标记设置为一种已调用状态。

    于是将想只调用一次的函数用call_once()进行包装

    void SystemInit()
    {
        cout << "Call SystemInit" << endl;
    }
    
    void SystemInitOne()
    {
        static std::once_flag flag;
        std::call_once(flag, SystemInit);
    }
    int main(int argc, char* argv[])
    {
        SystemInitOne();
        SystemInitOne();
        for (int i = 0; i < 3; i++)
        {
            thread th(SystemInitOne);
            th.detach();
        }
        getchar();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    可以看到,虽然for遍历了三次,但只调用了一次:
    在这里插入图片描述

  • 相关阅读:
    【Java 进阶篇】Ajax 实现——原生JS方式
    蓝桥杯算法竞赛系列第十章·nSum问题的代码框架
    信息系统项目管理师必背核心考点(七十三)黑/白/灰盒测试
    tcping下载安装步骤,如何ping端口,tcping详解
    上传图片和视频在JAVA上的运用
    AVT Prosilica GC Vision Cameras 相机视觉说明使用安装。具体详情内容可参看PDF目录内容。
    设计模式-代理模式-笔记
    78. 子集、90. 子集 II、491. 递增子序列
    虚拟机ubuntu22.04找不到ttyUSB*端口
    LeetCode 212.单词搜索Ⅱ Python题解
  • 原文地址:https://blog.csdn.net/qq_42567607/article/details/125464750