我已经使用 std::call_once 实现了线程安全的单例模式。我故意使用 std::move 将 std::unique_ptr 移动到 CallOnce 函数中,该函数由 std::call_once 调用。然而,在调用 std::call_once 之后,std::unique_ptr 没有设置为 nullptr。我预计在使用 std::move(pInstance) 之后,pInstance 会变为 nullptr。有人可以解释为什么会这样吗? 它可以作为参考传递,但我很想知道如果我使用 std::move 会发生什么。
另外,我的另一个问题是privGetInstance函数中的pInstance为null,那么当std::call_once被执行并返回时,其内容将与CallOnce函数中的pInstance局部变量相同。怎么可能?
#include <conio.h>
#include <thread>
#include <future>
#include <chrono>
struct ThreadCountProxy
{
public:
static void Increment()
{
std::unique_ptr<ThreadCountProxy>& pInstance = ThreadCountProxy::privGetInstance();
std::lock_guard<std::mutex> lock(pInstance->mtx);
++pInstance->count;
Debug::out("TC:%d \n", pInstance->count);
}
static void Decrement()
{
std::unique_ptr<ThreadCountProxy>& pInstance = ThreadCountProxy::privGetInstance();
std::lock_guard<std::mutex> lock(pInstance->mtx);
--pInstance->count;
Debug::out("TC:%d \n", pInstance->count);
if (pInstance->count == 0)
{
pInstance->cv_thread_count.notify_one();
}
}
static void WaitUntilThreadsDone()
{
std::unique_ptr<ThreadCountProxy>& pInstance = ThreadCountProxy::privGetInstance();
std::unique_lock<std::mutex> lock_ct(pInstance->mtx_thread_count);
pInstance->cv_thread_count.wait(lock_ct);
}
//static void CleanUp() //Release the memory
//{
// std::unique_ptr<ThreadCountProxy>& pInstance = ThreadCountProxy::privGetInstance();
// if (pInstance != nullptr)
// {
// //delete pInstance;
// //pInstance = nullptr;
// }
//}
~ThreadCountProxy() = default;
ThreadCountProxy() :
count(0), mtx(), mtx_thread_count(), cv_thread_count()
{
std::cout << "Default Constructor\n"; //This line shows how many instances are being created!
}
private:
static void CallOnce(std::unique_ptr<ThreadCountProxy>&& pInstance)
{
if (pInstance == nullptr)
{
pInstance = std::make_unique<ThreadCountProxy>();
}
}
static std::unique_ptr<ThreadCountProxy>& privGetInstance()
{
//std::this_thread::sleep_for(3s);
static std::once_flag flag;
static std::unique_ptr<ThreadCountProxy> pInstance;
std::call_once(flag, CallOnce,std::move(pInstance));
//if (pInstance == nullptr)
//{
// std::cout << "It is nullptr\n"; //It is used to test whether the Singleton Pattern is thread-safe and works properly or not
//}
return pInstance;
}
//Shared Data
int count;
std::mutex mtx; //This mutex is used for the 'count' variable
std::mutex mtx_thread_count; //This mutex is used for the signal
std::condition_variable cv_thread_count;
};
class ThreadCount
{
public:
ThreadCount()
{
ThreadCountProxy::Increment();
}
~ThreadCount()
{
ThreadCountProxy::Decrement();
}
};