首页 / 知识
关于多线程:C ++中单线程的线程安全惰性构造
2023-04-11 23:00:00

Thread safe lazy construction of a singleton in C++有没有一种方法可以在C ++中实现单例对象: (我不太了解我的C ++,但是是在执行任何代码之前初始化整数和常量静态变量的情况(即,甚至在执行静态构造函数之前-它们的值可能已经在程序中"初始化"了)如果是的话-也许可以利用它来实现单例互斥体-进而可以用来保护实际单例的创建。) 太好了,看来我现在有几个不错的答案(可惜我不能将2或3标记为答案)。似乎有两种广泛的解决方案:
不幸的是,Matt的答案具有所谓的双重检查锁定,而C / C ++内存模型不支持该功能。 (它受Java 1.5及更高版本(我认为是.NET)的内存模型的支持。)这意味着在发生
此外,正如Matt所承认的那样,他使用 如果您的操作系统提供了适当的原语,并且您绝对需要它来提高性能,则可以使用原子比较和交换操作来初始化共享的全局变量,而不是执行这种类型的锁定/初始化。本质上,您编写的内容将如下所示:
仅当可以安全地创建单个实例的多个实例(每个线程同时调用GetSingleton()的一个实例)安全然后丢弃其他对象时,此方法才有效。 Mac OS X上提供的
如果您的OS提供了介于这两个极端之间的另一个工具,则是 基本上,您要求同步创建一个单例,而不使用任何同步(先前构造的变量)。通常,这是不可能的。您需要一些可用于同步的东西。 关于您的其他问题,是的,可以静态初始化(即无需运行时代码)的静态变量保证在执行其他代码之前进行初始化。这样就可以使用静态初始化的互斥锁来同步单例的创建。 从2003年C ++标准修订版开始:
如果您知道在初始化其他静态对象时将使用此单例,那么我认为您会发现同步不是问题。据我所知,所有主要的编译器都在单个线程中初始化静态对象,因此在静态初始化期间具有线程安全性。您可以将单例指针声明为NULL,然后在使用它之前检查它是否已初始化。 但是,这假设您知道在静态初始化期间将使用此单例。标准也不能保证这一点,因此,如果要完全安全,请使用静态初始化的互斥锁。 编辑:克里斯的建议使用原子比较和交换肯定会奏效。如果可移植性不是问题(并且创建其他临时单例也不是问题),那么它是开销稍低的解决方案。 这是一个非常简单的惰性构造的单例getter:
这是懒惰的,下一个C ++标准(C ++ 0x)要求它必须是线程安全的。实际上,我相信至少g ++以线程安全的方式实现了这一点。因此,如果这是您的目标编译器,或者使用的编译器也以线程安全的方式实现此目标(也许较新的Visual Studio编译器可以呢?我不知道),那么这可能就是您所需要的。 另请参见http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2513.html关于此主题。 没有任何静态变量就无法做到这一点,但是,如果您愿意容忍一个,则可以使用Boost.Thread来实现此目的。阅读"一次性初始化"部分以了解更多信息。
然后在您的单例访问器函数中,使用 对于gcc,这非常简单:
GCC将确保初始化是原子的。对于VC ++,情况并非如此。 :-( 这种机制的一个主要问题是缺乏可测试性:如果您需要在两次测试之间将LazyType重置为新的,或者想要将LazyType *更改为MockLazyType *,则将无法进行测试。鉴于此,通常最好使用静态互斥体+静态指针。 另外,可能还有一个缺点:最好始终避免使用静态非POD类型。 (指向POD的指针是可以的。)这样做的原因有很多:正如您提到的,初始化顺序未定义-析构函数的调用顺序也未定义。因此,当程序尝试退出时,它们最终将崩溃。通常没什么大不了的,但是当您尝试使用的探查器时,有时需要关闭窗口。 读取弱内存模型。它可能会破坏双重检查的锁和自旋锁。英特尔是强大的内存模型(还可以),因此在英特尔上它更容易 谨慎使用" volatile",以避免将对象的部分缓存到寄存器中,否则,您将初始化对象指针,而不是对象本身,并且其他线程将崩溃 静态变量初始化与共享代码加载的顺序有时并不容易。我已经看到了用于销毁对象的代码已经卸载的情况,因此程序在退出时崩溃 这样的东西很难销毁 通常,单例很难正确地进行调试。最好完全避免使用它们。
OJ,那是行不通的。克里斯指出,这是双重检查锁定,不能保证在当前的C ++标准中可以使用。请参阅:C ++和双重检查锁定的风险 编辑:没问题,OJ。在可以使用的语言中,这确实很棒。我希望它可以在C ++ 0x中运行(尽管我不确定),因为它是一个方便的习惯用法。 尽管已经回答了这个问题,但我认为还有其他几点要提到:
但是,如上所述,如果不使用至少一个同步原语,就无法保证线程安全的延迟初始化。 编辑:是的德里克,你是对的。我的错。 :)
我想说不要这样做,因为这样做不安全,而且可能会比仅仅在 (是的,我知道这暗示着您不应尝试在全局对象的构造函数中做一些有趣的事情。这就是重点。) |
最新内容
相关内容
python如何确定是否为可迭代对象
python如何确定是否为可迭代对象,培训,元素,索引,对象,整数,字典,函数,类型,下标,模块,迭代可以理解为,任意的集合使用for循环遍历python中,迭python怎么判断某一对象是否为字典
python怎么判断某一对象是否为字典,培训,名称,代码,情况,类型,实例,元素,字典,函数,对象,我们经常需要在Python代码中确定某个实例是什么类型python如何查看对象属性
python如何查看对象属性,培训,网络,系统,函数,对象,属性,变量,示例,实例,模块,在Python语言中,有些库在使用时,在网络上找到的文档不全,这就需要python字符串是对象吗
python字符串是对象吗,培训,名称,设计,对象,函数,变量,实体,参数,物件,字符串,python中一切都是对象在python中下列语句其实都是一个共同点:i=python什么是面向对象
python什么是面向对象,概念,软件,设计,培训,数据,分析,状态,系统,统一,对象,python的面向对象的思维解决问题的重点当遇到一个需求的时候不用python创建多线程的两种方法
python创建多线程的两种方法,培训,第一,代码,业务,方法,线程,函数,任务,演示,实例,当我们使用python编程的过程中需要多个输出的任务的话,为了关于多线程:C#中是否有”尝试
关于多线程:C#中是否有尝试锁定,超时跳过操作?,关于多线程:C#中是否有尝试锁定,超时跳过操作?,锁定,超时,一个对象,语句,Is there a "try关于多线程:C#静态构造函数线程是否
关于多线程:C#静态构造函数线程是否安全?,关于多线程:C#静态构造函数线程是否安全?,线程,thread,safe,Singleton,Is the C# static constru关于测试:什么是对象模拟,何时需要?
关于测试:什么是对象模拟,何时需要?,关于测试:什么是对象模拟,何时需要?,对象,模拟,单元测试,框架,What is Object Mocking and when do I关于多线程:学习线程编程有哪些好的
关于多线程:学习线程编程有哪些好的资源?,关于多线程:学习线程编程有哪些好的资源?,财富,多线程技术,多核,学习,What are some good reso关于c#:测试对象类型的最有效方法
关于c#:测试对象类型的最有效方法,关于c#:测试对象类型的最有效方法,字符串,数据源,我将,导入,Most Efficient Way to Test Object Typ关于python:向现有对象实例添加方
关于python:向现有对象实例添加方法,关于python:向现有对象实例添加方法,方法,对象,类定义,这样做,Adding a Method to an Existing