函数局部静态const对象的线程安全初始化 [英] Thread-safe initialization of function-local static const objects

查看:194
本文介绍了函数局部静态const对象的线程安全初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题使我怀疑一个我一直在追踪多年的做法。



对于函数局部静态const对象的线程安全初始化,我保护对象的实际构造但不是引用它的函数局部引用的初始化。这样的东西:

 命名空间{
const some_type& create_const_thingy()
{
lock my_lock(some_mutex);
static const some_type the_const_thingy;
return the_const_thingy;
}
}

void use_const_thingy()
{
static const some_type& the_const_thingy = create_const_thingy();

//使用the_const_thingy

}

想法是锁需要时间,如果引用被几个线程覆盖,这没关系。



如果这是

,我会感兴趣的。



  1. 根据规则安全吗? (我知道,当前的标准甚至不知道什么是并发,但是如何践踏一个已经初始化的引用?而其他标准,如POSIX,有什么说的与这个相关?)

我想知道的原因是我想知道我是否可以离开代码,或者我是否需要去


$ b
$ b

我使用的许多这样的函数局部静态const对象是在首次使用时从const数组初始化并用于查找的映射。例如,我有一些XML解析器,其中标签名字符串映射到枚举值,所以我可以以后 switch 通过标签的枚举值。






由于我已经得到了一些答案,但是没有回答我的实际问题见上面的1.和2.),我会开始一个赏金这个。再次:

我对我可以做的事情不感兴趣,而是
,我真的想知道

解决方案

这是我第二次尝试回答。我只会回答您的第一个问题:



  1. 在实践中足够安全吗?


否。因为你表示自己,你只是确保对象创建是受保护的,而不是对对象的引用的初始化。



没有C ++ 98内存模型,并且没有来自编译器供应商的显式语句,不能保证写入存储器表示实际引用和写入存储器,其保持初始化标志的值(如果这是如何实现的)用于



正如你也说的,用相同的值重写引用几次不会产生语义上的差异(即使在存在的字撕裂,这通常是不可能的,也许甚至不可能在你的处理器架构),但有一个情况下,重要的是:当多个线程竞争在程序执行时第一次调用该函数。在这种情况下,这些线程中的一个或多个可能在实际引用被初始化之前看到初始化标志被设置。



你的程序中有一个潜在的错误你需要修复它。至于优化,我敢肯定有很多除了使用双检查锁定模式。


This question made me question a practice I had been following for years.

For thread-safe initialization of function-local static const objects I protect the actual construction of the object, but not the initialization of the function-local reference referring to it. Something like this:

namespace {
  const some_type& create_const_thingy()
  {
     lock my_lock(some_mutex);
     static const some_type the_const_thingy;
     return the_const_thingy;
  }
}

void use_const_thingy()
{
  static const some_type& the_const_thingy = create_const_thingy();

  // use the_const_thingy

}

The idea is that locking takes time, and if the reference is overwritten by several threads, it won't matter.

I'd be interested if this is

  1. safe enough in practice?
  2. safe according to The Rules? (I know, the current standard doesn't even know what "concurrency" is, but what about trampling over an already initialized reference? And do other standards, like POSIX, have something to say that's relevant to this?)

The reason I want to know this is that I want to know whether I can leave the code as it is or whether I need to go back and fix this.


For the inquiring minds:

Many such function-local static const objects I used are maps which are initialized from const arrays upon first use and used for lookup. For example, I have a few XML parsers where tag name strings are mapped to enum values, so I could later switch over the tags' enum values.


Since I got some answers as to what to do instead, but haven't got an answer to my actual questions (see 1. and 2. above), I'll start a bounty on this. Again:
I am not interested in what I could do instead, I do really want to know about this.

解决方案

This is my second attempt at an answer. I'll only answer the first of your questions:

  1. safe enough in practice?

No. As you're stating yourself you're only ensuring that the object creation is protected, not the initialization of the reference to the object.

In absence of a C++98 memory model and no explicit statements from the compiler vendor, there are no guarantees that writing to the memory representing the actual reference and the writing to the memory that holds the value of the initialization flag (if that is how it is implemented) for the reference are seen in the same order from multiple threads.

As you also say, overwriting the reference several times with the same value should make no semantic difference (even in the presence of word tearing, which is generally unlikely and perhaps even impossible on your processor architecture) but there's one case where it matters: When more than one thread races to call the function for the first time during program execution. In this case it is possible for one or more of these threads to see the initialization flag being set before the actual reference is initialized.

You have a latent bug in your program and you need to fix it. As for optimizations I'm sure there are many besides using the double-checked locking pattern.

这篇关于函数局部静态const对象的线程安全初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆