一、单次调用开发者很容易混淆单次调用和单实例两种机制可能觉得二者没有区别。在前面的分析中对单实例也就是唯一对象的处理进行过实现分析而且其中的实施也使用了单次调用的方法。单次调用不仅可以用在生成单实例上也可以用在普通的多实例上。单次调用的价值在于对外不会产生副作用无论从形式上或内容上都保持了正常开发的调用机制但达到了只进行唯一一次调用的过程。单次调用的应用场景非常丰富比如常见的单实例、多线程的安全调用以及在某些特殊平台上的接口单一控制如硬件的初始化等等。二、为什么需要单次调用C中处理单次调用的目的主要有以下几个减少重复调用提高效率防止多线程出现多次调用产生竞态导致状态的不稳定进而引发程序的异常重复初始化导致的配置异常导致运行结果的问题硬件平台不支持重复初始化可能导致软、硬件异常设计模式如单实例的需要单次调用某些情况下支持延迟加载提高加载速度架构设计或功能的需要三、C的应对方法在C中要想实现单次调用的方式其实非常简单。当然这是指在较新的C标准情况下。一般来说推荐使用的方法主要有std::call_once这是推荐的使用方法通过std::call_once和std::once_flag配合可以达到对接口的单次调用的目的懒汉模式。它可以保证在多线程调用的情况下接口只被调用一次。这也是创建单实例的一重要方式。它的优势在于全方位的操作能力容易维护但对标准要求稍高C11及以后。显式的全局调用这种情况一般只在程序启动时调用一次接口以后则不再允许调用饿汉模式。这种情况涉及不到多线程也涉及不到复杂的调用操作简单便于维护管理。但缺点也比较明显无法防止开发者重复、忽略调用。这更像是一种业务逻辑的控制而非技术层面的控制。局部或inline静态调用局部静态调用这个在C11后已经由编译器保证了多线程的安全性在C17后的inline静态变量也提供了类似的机制。区别在于局部静态变量标准是保证其初始化的多线程安全的而inline静态变量则只保证全局的唯一性而无法保证多线程的安全初始化。也就是说它更适合于显式的全局调用中使用。这类机制的缺点在于无法进行顺利的动态沟通包括初始化出现问题的异常处理都存在着风险。使用同步操作包括使用互斥锁或使用原子锁以及类似智能指针的引用计数器控制都可以实现单次调用的目的但操作复杂效率较低还容易出现各种细节的处理问题。四、实例根据上面的情况给出几个例程非常简单//call once#includemutex#includethreadstd::once_flag flag_;voidoneInit(){// 只执行一次std::coutcall once!std::endl;}voidthreadFunc(){std::call_once(flag_,oneInit);}//局部静态变量Demo*callOnceOp(){//处理returnpDemo;}voidoneStaticFunc(){staticDemo*pcallOnceOp();}//inline静态class CallOnceDemo{public:staticinlineCallOnceDemoins[]()-CallOnceDemo{staticCallOnceDemo obj;returnobj;}();};重点是把代码与分析对应而不是简单的看这些简单的代码。五、总结为什么强调要把基础打扎实因为这是为后来将多种技术点融合的一个重要前提。正如战场技击拳打还是脚踢其具体到每个动作招式都是一样的但每次的对手和环境不同那么出手的先后顺序和应对方式都有所不同。这就需要每个人能灵活的判断当前的具体情况到底采用哪种技击的招式。僵化的使用招式结果就只能是挨打。明白这个道理也就明白了开发中为什么每个功能的实现后面会跟着多种实现的机制而每种实现机制又不只是单纯为这种功能服务的原因了。