C++并发与多线程 单例模式共享数据分析与问题解决、call_once

单例模式介绍与例子

单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例
例子如下:

using namespace std;
class single
{
private:
	single() {}
private:
	static single * instance;
public:
	static single* Getinstance()
	{
		if (instance = nullptr)
		{
			instance = new single();
			static CG cg;
		}
		return instance;
	}
	class CG //用来回收对象
	{
	public:
		~CG() 
		{
			if (single::instance)
			{
				delete single::instance;
				single::instance = nullptr;
			}
		}
	};
	void test()
	{
		cout << "测试" << endl;
	}
};

single *single::instance = nullptr;
int main()
{
	single * s = single::Getinstance();
	s->test();
	single::Getinstance()->test();
}

在这里插入图片描述

单例模式共享数据分析与问题解决

第一个问题:除了主线程外,我们可以还需要在其他线程中创建single这个单例类的对象,这就涉及到了互斥。
比如

void func()
{
	cout << "线程开始了,线程ID为: " << this_thread::get_id() << endl;
	single * s = single::Getinstance();
	cout << "线程结束,线程ID为:" << this_thread::get_id() << endl;
}

single *single::instance = nullptr;
int main()
{
	thread t(func);
	thread t1(func);
	t.join();
	t1.join();
	return 0;

}

解决办法:使用双重锁定

	static single* Getinstance()
	{

		if (instance == nullptr)//双重锁定,因为if(instance == nullptr)不代表instance一定没被new
		{
			unique_lock<mutex>lock(mymutex);//加锁
			if (instance == nullptr)
			{
				instance = new single();
				static CG cg;
			}
		}
		return instance;
	}

std::call_once()

头文件<mutex>

在这里插入图片描述
C++11引入的函数,该函数的第二个参数是一个可调用对象,它的作用是保证该对象只调用一次.具备互斥能力,而且 性能更好。
需要和标记结合使用,这个标记是std::once_flag

工作原理:

call_once使用标记来确定对应的调用对象是否执行,调用call_once成功后,call_once就把这个标记设置为已调用状态,下次对应的对象就不会在执行了.
在这里插入图片描述
可以看到里面有一个void*成员初始化的时候设置为nullptr,当使用了一次这个指针就不是nullptr,通过判断是否为nullptr来推测出是否已经调用.

mutex  mymutex;
once_flag flag;
class single
{
private:
	single() {}
private:
	static void CreateInstance()//只被调用一次
	{
		cout << "CreateInstance执行了!" << endl;
		instance = new single();
		static CG cg;
	}
	static single * instance;
public:
	static single* Getinstance()
	{
		call_once(flag, CreateInstance);
		return instance;
	}
	class CG //用来回收对象
	{
	public:
		~CG() 
		{
			if (single::instance)
			{
				delete single::instance;
				single::instance = nullptr;
			}
		}
	};
	void test()
	{
		cout << "测试" << endl;
	}
};
void func()
{
	cout << "线程开始了,线程ID为: " << this_thread::get_id() << endl;
	single * s = single::Getinstance();
	cout << "线程结束,线程ID为:" << this_thread::get_id() << endl;
}

single *single::instance = nullptr;
int main()
{
	thread t(func);
	thread t1(func);
	t.join();
	t1.join();
	return 0;

}

在这里插入图片描述

可以看到CreateInstance只调用了一次!

猜你喜欢

转载自blog.csdn.net/qq_44800780/article/details/104861424