如何在不使用 <mutex> 的情况下在 C++11 中实现多线程安全单例 [英] How to implement multithread safe singleton in C++11 without using <mutex>

查看:28
本文介绍了如何在不使用 <mutex> 的情况下在 C++11 中实现多线程安全单例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

既然 C++11 具有多线程,我想知道在不使用互斥体的情况下实现延迟初始化单例的正确方法是什么(出于性能原因).我想出了这个,但是我不太擅长编写无锁代码,所以我正在寻找一些更好的解决方案.

Now that C++11 has multithreading I was wondering what is the correct way to implement lazy initialized singleton without using mutexes(for perf reasons). I came up with this, but tbh Im not really good at writing lockfree code, so Im looking for some better solutions.

// ConsoleApplication1.cpp : Defines the entry point for the console application.
//
# include <atomic>
# include <thread>
# include <string>
# include <iostream>
using namespace std;
class Singleton
{

public:
    Singleton()
    {
    }
static  bool isInitialized()
    {
        return (flag==2);
    }
static  bool initizalize(const string& name_)
    {
        if (flag==2)
            return false;// already initialized
        if (flag==1)
            return false;//somebody else is initializing
        if (flag==0)
        {
            int exp=0;
            int desr=1;
            //bool atomic_compare_exchange_strong(std::atomic<T>* obj, T* exp, T desr)
            bool willInitialize=std::atomic_compare_exchange_strong(&flag, &exp, desr);
            if (! willInitialize)
            {
                //some other thread CASed before us
                std::cout<<"somebody else CASed at aprox same time"<< endl;
                return false;
            }
            else 
            {
                initialize_impl(name_);
                assert(flag==1);
                flag=2;
                return true;
            }
        }
    }
static void clear()
{
    name.clear();
    flag=0;
}
private:
static  void initialize_impl(const string& name_)
{
        name=name_;
}
static  atomic<int> flag;
static  string name;
};
atomic<int> Singleton::flag=0;
string Singleton::name;
void myThreadFunction()
{
    Singleton s;
    bool initializedByMe =s.initizalize("1701");
    if (initializedByMe)
        s.clear();

}
int main()
{
    while (true)
    {
        std::thread t1(myThreadFunction);
        std::thread t2(myThreadFunction);
        t1.join();
        t2.join();
    }
    return 0;
}

注意 clear() 只是为了测试,真正的单例没有那个功能.

Note that clear() is just for testing, real singleton wouldnt have that function.

推荐答案

C++11 消除了手动锁定的需要.如果静态局部变量已经被初始化,并发执行将等待.

C++11 removes the need for manual locking. Concurrent execution shall wait if a static local variable is already being initialized.

§6.7 [stmt.dcl] p4

如果在初始化变量的同时控制进入声明,则并发执行将等待初始化完成.

If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.

因此,简单有一个 static 函数,如下所示:

As such, simple have a static function like this:

static Singleton& get() {
  static Singleton instance;
  return instance;
}

这将在 C++11 中正常工作(当然,只要编译器正确实现了标准的那部分).

This will work all-right in C++11 (as long as the compiler properly implements that part of the standard, of course).

当然,真正的正确答案是使用单例句点.

Of course, the real correct answer is to not use a singleton, period.

这篇关于如何在不使用 &lt;mutex&gt; 的情况下在 C++11 中实现多线程安全单例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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