从两个不同的线程同时第一次访问singleton类

Simultaneous first time access of singleton class from two different threads

本文关键字:线程 第一次 访问 singleton 两个      更新时间:2023-10-16

在我的C++项目中,我有一个singleton类。在项目执行期间,有时从两个不同的线程同时访问同一个singleton类。导致生成了singleton类的两个实例,这是一个问题。

如何处理这样的案件?

那么它不是单例:-)

您可能需要向我们展示一些代码,但您的基本问题是同步区域。

如果做得好,两个线程可以创建类的两个对象的方式就不存在了。事实上,类本身应该是强制执行singleton特性的地方,这样错误的客户端就不会破坏意图。

基本结构为:

lock mutex
if instance doesn't exist:
    instance = new object
unlock mutex

如果没有互斥锁保护之类的东西(或者关键代码段,或者任何其他可以在语言/库级别保证两个线程不能同时运行代码的方式),线程一可能会在检查和实例化之间交换,从而导致两个可能的"单例"实例。

而且,正如其他人无疑会暗示的那样,单身很可能是个坏主意。我不太喜欢每一次的使用都是错误的,通常的问题是人们把它们当作"上帝"的物体。它们可以有自己的用途,但通常有更好的方法,尽管我不会冒昧地告诉你你需要更改,因为我不知道你的用例。

如果在不同的线程中获得两个不同的实例,则说明您做错了什么。与进程不同,线程共享它们的内存。因此,在一个线程中分配的内存(例如,为对象实例分配的内存)也可用于另一个线程。

如果您的单例获得两个副本,那么它就没有用互斥锁保护。获取/访问/设置内部对象时锁定互斥对象。

我相信你做了这样的事情if(!_instance)_instance = new Singleton()有一个关键部分。你需要用互斥锁来保护它。

不要使用singleton,它是众所周知的反模式
一本好书:
辛格尔顿:解决自1995年以来从未遇到过的问题

如果你仍然想坚持并继续它,原因只有你自己知道,你需要的是一个线程安全的单例实现,比如这样的:

YourClass* YourClass::getInstance()
{
    MutexLocker locker(YourClass::m_mutex);
    if(!m_instanceFlag)
    {
        m_instance = new YourClass();
        m_instanceFlag = true;
    }
    return m_instance;
}

其中MutexLocker是通常使用的互斥体的包装类,它在创建其实例时锁定互斥体,并解锁互斥体,函数结束。