简体   繁体   English

初学者 C++ 线程安全 singleton 设计

[英]beginner's C++ thread-safe singleton design

I wish to create a static Class object which should stay in the memory while the program is running.我希望创建一个 static Class object 在程序运行时应该留在 ZCD69B4957F06CD818D7BF3D61980E9 中The object needs to be initialized only once by the init function and the output function will be called in a static method always. The object needs to be initialized only once by the init function and the output function will be called in a static method always. Does my code make sense and is it thread-safe?我的代码有意义吗?它是线程安全的吗?

class Singleton
{
public: 
       static void init(const int value)
       {
              static Singleton inst;
              inst.Value = value;
       }
       static int prnValue()
       {
               return Value;
       }

private:
       Singleton() {};
       static int Value;
};

int main()
{
       int inputValue = 10;

       Singleton::init(inputValue);
       cout << Singleton::prnValue();

       return 0;
}

New Edit: Or can I try like this then?新编辑:或者我可以这样尝试吗?

class Singleton
{
public: 
       static Singleton& init(const int value)
       {
              static Singleton inst;
              inst.Value = value;

              return inst;
       }
       static int prnValue()
       {
               return Value;
       }

private:
       Singleton() {};
       static int Value;
};

Addition: Meyer's singleton example look like另外: Meyer 的 singleton 示例看起来像

class Singleton
{
public: 
       static Singleton& init()
       {
              static Singleton inst;

              return inst;
       }

private:
       Singleton() {};
};

So Isn't my code consistent with Meyer's example?那么我的代码与 Meyer 的示例不一致吗?

Try4: How about this? Try4:这个怎么样?

class Singleton
{
public: 
       static Singleton& init(int value)
       {
              static Singleton inst(value);
              return inst;
       }
       static int prnValue()
       {
               return Value;
       }
private:
       Singleton(value) 
       {
              Value = value;
       }
       int Value;
};

Added comment: How to pass argument in a singleton seems to provide the same answer as Try4.添加评论: 如何在 singleton 中传递参数似乎提供了与 Try4 相同的答案。

The first is just a very convoluted global variable.第一个只是一个非常复杂的全局变量。 There is no need for the instance.不需要实例。 inst.Value = value; is an obfuscated way to write Singleton.Value = value;是一种混淆的方式来写Singleton.Value = value; . . Really no offense, but I do not understand what should be the purpose of this code.真的没有冒犯,但我不明白这段代码的目的是什么。

The second does return the instance, but that doesnt make the situation much better compared to the first.第二个确实返回了实例,但这并没有使情况比第一个好得多。 The instance has no non-static members and cannot be used for anything that you couldnt do without it.该实例没有非静态成员,不能用于任何没有它就不能做的事情。 It basically is similar to the first.基本上和第一个差不多。

As you are asking for thread-safety, there is none.当您要求线程安全时,没有。 Two threads may call init with differernt values and you will have two threads writing to the same memory resulting in a data race.两个线程可能会调用具有不同值的init ,并且您将有两个线程写入相同的 memory 导致数据竞争。

You should read about the Meyers singleton.您应该阅读有关 Meyers singleton 的信息。 It is based on the fact that function local static variables are guaranteed (not sure but I think since C++11, someone correct me in case I am wrong) to be initialized only once in a thread-safe way.这是基于 function 本地 static 变量得到保证的事实(不确定,但我认为自从 C++11 以来,只有有人纠正我,以防我以线程安全的方式初始化一次)。 To demonstrate only this aspect, consider:为了仅演示这方面,请考虑:

struct Foo {
    static void bar(int x) {
        static int y = x; 
    }
};

This is thread-safe without any further measures to be taken, because y is guaranteed to be initialized only once.这是线程安全的,无需采取任何进一步的措施,因为y保证只被初始化一次。

In your code however, you have但是,在您的代码中,您有

static Singleton& init(const int value)
{
   static Singleton inst;
   inst.Value = value;     // <---
   return inst;
}

And in the line marked with the comment you do not get the nice feature of initialization of local static variables (initialized exactly once), hence you have a race condition.在标有注释的行中,您没有获得本地 static 变量初始化的好功能(仅初始化一次),因此您有竞争条件。

My intention is to store the int value 10 throught the program我的意图是通过程序存储 int 值 10

That is not a singleton but rather a那不是 singleton 而是

constexpr const int value = 10;

Globals should be avoided, but using a singleton is not avoiding a global.应该避免使用全局变量,但使用 singleton 并不能避免全局变量。 A singleton is a global. singleton全球性的。 Rules have exceptions.规则有例外。 Once you decided you really want to have a constant with value 10 that you can use throughout your program, you do have a global, so just use one.一旦你决定你真的想要一个可以在整个程序中使用的值为10的常量,你确实有一个全局的,所以只使用一个。

Abandon Singleton and make Value a const global variable initialized with a helper function.放弃 Singleton 并使Value成为使用帮助程序 function 初始化的const全局变量。

Example:例子:

// anonymous namespace to bind the global to this file to prevent the static 
// initialization order fiasco
namespace 
{
    const int Value = ReadIniFile("section", "key", default_value);
}

But what if you need to use this variable in other files?但是如果你需要在其他文件中使用这个变量呢? The best advice I've got is don't.我得到的最好的建议是不要。 But if you must, the static initialization order fiasco needs to be overcome.但是,如果必须,则需要克服static 初始化命令的惨败 Here's a quick way to do that that is similar to what you've seen so far:这是一种与您目前看到的类似的快速方法:

// Lazy loader function similar to Meyers Singleton
int Value()
{
    static int value = ReadIniFile("section", "key", default_value);
    return value;
}

Usage:用法:

me_function_need_Value(Value());

This ensures that Value is initialized before anyone can try to use it no matter which file in your project needs it.这可确保在任何人尝试使用它之前初始化Value ,无论项目中的哪个文件需要它。 Unfortunately it's now hard to figure out when it goes out of scope, so the problem doesn't really go away.不幸的是,现在很难弄清楚它什么时候会从 scope 中消失,所以问题并不是真正的 go。 It's just moved from the start of the program to the end where it is a little more manageable.它只是从程序的开头移到了更易于管理的结尾。 See Destruction order of static objects in C++ .请参阅C++ 中 static 对象的销毁顺序 Ensure no one uses Value after main exits and you'll be safe.确保在main退出后没有人使用Value ,这样你就安全了。 Still, use with caution.不过,请谨慎使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM