单线程与多线程

mad*_*adu 22 c++ singleton multithreading synchronization mutex

在一次采访中询问了这个问题.第一部分是编写单例类:

class Singleton
{
    static Singleton *singletonInstance;
    Singleton() {}

  public:
    static Singleton* getSingletonInstance()
    {
        if(singletonInstance == null)
        {
            singletonInstance = new Singleton();
        }
        return singletonInstance;
    }
};
Run Code Online (Sandbox Code Playgroud)

然后我被问到如何getSingletonInstance()在多线程情况下处理这个问题.我不太确定,但我修改为:

class Singleton 
{
    static Singleton *singletonInstance;
    Singleton() {}
    static mutex m_;

  public:
    static Singleton* getSingletonInstance()
    {
        m_pend();
        if(singletonInstance == null)
        {
            singletonInstance = new Singleton();
        }
        return singletonInstance;
    }

    static void releaseSingleton()
    {
        m_post();
    }
};
Run Code Online (Sandbox Code Playgroud)

然后有人告诉我,虽然需要一个互斥锁,但挂起和发布互斥锁效率不高,因为需要时间.并且有一种更好的方法来应对这种情况.

有没有人知道在多线程情况下处理单例类的更好,更有效的方法?

Mik*_*our 29

在C++ 11中,保证以下内容执行线程安全初始化:

static Singleton* getSingletonInstance()
{
    static Singleton instance;
    return &instance;
}
Run Code Online (Sandbox Code Playgroud)

在C++ 03中,一种常见的方法是使用双重检查锁定; 检查一个标志(或指针本身)以查看该对象是否未被初始化,并且仅在可能存在的情况下锁定该互斥锁.这需要某种非标准的原子方式读取指针(或相关的布尔标志); 许多实现错误地使用普通指针,或者bool不保证一个处理器上的更改在其他处理器上可见.代码可能看起来像这样,虽然我几乎肯定有错误:

static Singleton* getSingletonInstance()
{
    if (!atomic_read(singletonInstance)) {
        mutex_lock lock(mutex);
        if (!atomic_read(singletonInstance)) {
            atomic_write(singletonInstance, new Singleton);
        }
    }
    return singletonInstance;
}
Run Code Online (Sandbox Code Playgroud)

这是非常棘手的,所以我建议你不要打扰.在C++ 11中,您可以使用标准的原子和互斥类型,如果由于某种原因您希望保持动态分配示例.

请注意,我只讨论同步初始化,而不是对对象的同步访问(您的版本通过锁定访问器中的互斥锁,以及稍后通过单独的函数释放它来提供).如果您需要锁来安全地访问对象本身,那么您显然无法避免锁定每次访问.


Pet*_*ker 14

正如@piokuc建议的那样,你也可以在这里使用一次函数.如果你有C++ 11:

#include <mutex>

static void init_singleton() {
    singletonInstance = new Singleton;
}
static std::once_flag singleton_flag;

Singleton* getSingletonInstance() {
    std::call_once(singleton_flag, init_singleton);
    return singletonInstance;
}
Run Code Online (Sandbox Code Playgroud)

并且,是的,如果new Singleton抛出异常,这将合理地工作.

  • 谢谢。我不知道曾经的功能。 (2认同)