Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 单线程多线程_C++_Multithreading_Synchronization_Singleton_Mutex - Fatal编程技术网

C++ 单线程多线程

C++ 单线程多线程,c++,multithreading,synchronization,singleton,mutex,C++,Multithreading,Synchronization,Singleton,Mutex,这个问题是在一次采访中提出的。第一部分是编写singleton类: class Singleton { static Singleton *singletonInstance; Singleton() {} public: static Singleton* getSingletonInstance() { if(singletonInstance == null) { singletonInstanc

这个问题是在一次采访中提出的。第一部分是编写singleton类:

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

  public:
    static Singleton* getSingletonInstance()
    {
        if(singletonInstance == null)
        {
            singletonInstance = new Singleton();
        }
        return singletonInstance;
    }
};
然后有人问我如何在多线程情况下处理这个
getsingletonistance()
。我不是很确定,但我修改为:

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();
    }
};
然后我被告知,虽然需要一个互斥体,但挂起和发布互斥体并不高效,因为它需要时间。还有更好的方法来处理这种情况


有谁知道在多线程情况下处理singleton类的更好、更有效的方法吗?

如果你有C++11,你可以将singletonInstance设置为原子变量,然后使用双重检查锁:

if (singletonInstance == NULL) {
    lock the mutex
    if (singletonInstance == NULL) {
        singletonInstance = new Singleton;
    }
    unlock the mutex
}
return singletonInstance;

实际上应该锁定单例,而不是实例。如果实例需要锁定,则该锁定应由调用方处理(或者由实例本身处理,具体取决于它公开的接口类型)

更新示例代码:

#include <mutex>

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

  public:

    static Singleton* getSingletonInstance()
    {
        std::lock_guard<std::mutex> lock(m_);
        if(singletonInstance == nullptr)
        {
            singletonInstance = new Singleton();
        }
        return singletonInstance;
    }
}
#包括
单件阶级
{
静态单态*单态;
Singleton(){}
静态std::互斥m_;
公众:
静态单例*getSingletonInstance()
{
标准:锁和防护锁(m);
if(singletonistance==nullptr)
{
singletonistance=新的Singleton();
}
回归单一立场;
}
}

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

static Singleton* getSingletonInstance()
{
    static Singleton instance;
    return &instance;
}
在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;
}
这是相当棘手的正确,所以我建议你不要麻烦。在C++11中,如果出于某种原因希望保持示例的动态分配,可以使用标准原子和互斥类型


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

如果您使用POSIX线程,您可以使用
pthread\u一次
pthread\u key\t
之类的东西,这样您就可以避免完全使用互斥锁。例如:

template<class T> class ThreadSingleton : private NonCopyable {
public:
    ThreadSingleton();
    ~ThreadSingleton();

    static T& instance();

private:
    ThreadSingleton( const ThreadSingleton& );
    const ThreadSingleton& operator=( const ThreadSingleton& )

    static pthread_once_t once_;
    static pthread_key_t  key_;

    static void init(void);
    static void cleanUp(void*);
};
模板类ThreadSingleton:私有不可复制{
公众:
ThreadSingleton();
~ThreadSingleton();
静态T&实例();
私人:
ThreadSingleton(const ThreadSingleton&);
常量ThreadSingleton&运算符=(常量ThreadSingleton&)
静态pthread_once_t once;
静态pthread\u key\u t key;
静态void init(void);
静态空洞清理(空洞*);
};
和执行:

template<class T> pthread_once_t ThreadSingleton<T>::once_ = PTHREAD_ONCE_INIT;
template<class T> pthread_key_t ThreadSingleton<T>::key_;

template<class T>  
T& ThreadSingleton<T>::instance()
{
    pthread_once(&once_,init);

    T* value = (T*)pthread_getspecific(key_);
    if(!value)
    {   

        value = new T();
        pthread_setspecific(key_,value);
    }   
    return *value;
}

template<class T> void ThreadSingleton<T>::cleanUp(void* data)
{
    delete (T*)data;
    pthread_setspecific(key_,0);
}

template<class T> void ThreadSingleton<T>::init()
{
    pthread_key_create(&key_,cleanUp);
}
template pthread\u once\t ThreadSingleton::once\u=pthread\u once\u INIT;
模板pthread_key_t ThreadSingleton::key;
模板
T&ThreadSingleton::instance()
{
pthread_once(&once_,init);
T*value=(T*)pthread\u getspecific(key);
如果(!值)
{   
值=新的T();
pthread_setspecific(键,值);
}   
返回*值;
}
模板void ThreadSingleton::cleanUp(void*数据)
{
删除(T*)数据;
pthread_setspecific(键0);
}
模板void ThreadSingleton::init()
{
pthread_key_创建(&key_,清理);
}

正如@piokuc所建议的,您也可以在此处使用once函数。如果您有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;
}
#包括
静态void init_singleton(){
singletonistance=新的Singleton;
}
静态std::once_标志singleton_标志;
Singleton*getsingletonistance(){
std::call_once(singleton_标志,init_singleton);
回归单一立场;
}

是的,如果新的单例抛出异常,这将非常有效。

根本不使用单例?在多线程代码中使用全局状态是一种解决无限麻烦的好方法。“愚蠢的格尔顿的情况更是如此。”卡普卢斯:这是个傻瓜。如果你的编译器正确地实现了C++11,你根本不需要锁定它
static Foo&getSingleton(){static Foo Foo{};return Foo;}
将只在并发执行下工作。@Xeo-这一点很好。回答这个问题,我会投赞成票,但有一条评论说,这可能是低效的,这取决于编译器如何管理函数静态对象的锁(如果有一个共享锁,您可能会遇到争用)。好吧,我已经写了一个,但问题并不是真的重复,至少在我看来:。如果要显式地为“解锁互斥锁”编写一行伪代码,那么伪代码是否也应该确保在
new
表达式抛出时将其解锁?或者可以不用说,假设异常导致程序终止吗?在一个真正的程序中,你必须决定哪一个,所以我真的认为我在这里谈论的是伪代码礼仪…@SteveJessop-你的意思是正确的,如果分配引发异常,解锁必须完成。我只是尽量避免调用
m_pend()
m_post()
,就像在原始代码中一样,因为我不知道它们会做什么。当然,在C++11中,您会使用一个锁对象,其析构函数会解锁互斥锁。我认为问题在于创建一个实例,而不是每个线程一个。我不是这样理解这个问题的。。我刚刚又读了一遍,我想你是对的。对不起,谢谢。我不知道once函数。@PeteBecker这是最好的答案,std ns的完美使用。@PeteBecker getSingletonInstance()是非静态的,这是singleton模式的问题,您必须将其设置为静态。@Yogesh-在我编写的代码中,
getSingle