c++11新特性-下

c++11的线程库可以跨平台使用。

原子性操作库(atomic)

不需要对原子类型变量进行加锁解锁操作,线程能够对原子类型变量互斥的访问。

atmoic<T> t; // 声明一个类型为T的原子类型变量t

在C++11中,原子类 型只能从其模板参数中进行构造,不允许原子类型进行拷贝构造、移动构造以及operator=

#include <atomic>
int main()
{
 atomic<int> a1(0);
 //atomic<int> a2(a1); // 编译失败
 atomic<int> a2(0);
 //a2 = a1; // 编译失败
 return 0;
}

thread的使用

仿函数配合thread使用

//仿函数配合thread使用
atomic<int> x = 0;
struct Add
{
	void operator()(int n)
	{
		for (int i = 0; i < n; ++i)
			++x;
	}
};
thread t1(Add(), 1000000);

 也可以使用匿名对象。

lambda配合thread使用

atomic<int> x = 0;
auto add = [&x](int n) {
	for (int i = 0; i < n; ++i)
		++x;
	};
thread t1(add, 1000000);
thread t2(add, 1000000);
cout << t1.get_id() << endl;
cout << t2.get_id() << endl;
t1.join();
t2.join();
cout << x << endl;

优化:

atomic<int> x = 0;
int m, n;
cin >> m >> n;
vector<thread> vthreads;
for (int i = 0; i < m; ++i)
{
	vthreads.push_back(thread([&x](int count) {
		for (int i = 0; i < count; ++i)
			++x;
	}, n));
}
for (auto& t : vthreads)
{
	cout << t.get_id() << ".join()" << endl;
	t.join();
}
cout << x << endl;
vector<thread> vthreads(m);
for (int i = 0; i < m; ++i)
{
	vthreads[i]=thread([&x](int count) {
		for (int i = 0; i < count; ++i)
			++x;
		}, n);
}

让两个线程分别打印奇偶数

int n = 10;
mutex mtx1, mtx2;
condition_variable cv1, cv2;
thread t1([&]() 
	{
	for (int i = 0; i < n; i += 2)
	{
		
		cout << this_thread::get_id() << ":" << i << endl;
		cv2.notify_one();
		cv1.wait((unique_lock<mutex>&)unique_lock<mutex>(mtx1));
	}
	});
thread t2([&]() {
	for (int i = 1; i < n; i += 2)
	{
		cv2.wait((unique_lock<mutex>&)unique_lock<mutex>(mtx2));
		cout << this_thread::get_id() << ":" << i << endl;
		cv1.notify_one();
	}
	});
t1.join();
t2.join();

throw可以抛出任意类型的对象。

catch(...)可以捕获任意类型的异常,问题是不知道异常错误是什么。

double Division(int a, int b)
{
 // 当b == 0时抛出异常
 if (b == 0)
 throw "Division by zero condition!";
 else 
 return ((double)a / (double)b);
}
 
void Func()
{
 int len, time;
 cin >> len >> time;
 cout << Division(len, time) << endl;
}
int main()
{
 try {
 Func();
 }
 catch (const char* errmsg) {
 cout << errmsg << endl;
 }
 catch(...){
 cout<<"unkown exception"<<endl; 
 }
 
 return 0;
}

智能指针

template<class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{}
	~SmartPtr()
	{
		if (_ptr)
		{
			cout << "delete: " << _ptr << endl;
			delete _ptr;
		}
	}
private:
	T* _ptr;
};

RAII是一种托管资源的方式,智能指针是依靠这种RAII实现的。

C++98  auto_ptr

将管理权转移

缺陷:ap2=ap1时,ap1将悬空,访问就会报错。

auto_ptr<int> ap1(new int);
auto_ptr<int> ap2 = ap1;

C++11 unique_ptr

缺陷:无法应对需要拷贝的场景。

unique_ptr<int> ap1(new int);

C++11 shared_ptr

namespace sp
{
	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr)
			:_ptr(ptr)
			,_pcount(new int(1))
		{}
		shared_ptr(shared_ptr<T>& sp)
			:_ptr(sp._str)
			, _pcount(new int(1))
		{
			++(*_pcount);
		}
		
		~shared_ptr()
		{
			if (--(*_pcount)==0&&_ptr)
			{
				cout << "delete: " << _ptr << endl;
				delete _ptr;
				_ptr = nullptr;
			}
		}
	private:
		T* _ptr;
		int* _pcount;
	};
}
//sp1=sp4
		shared_ptr<T>& operator=(shared_ptr<T>& sp)
		{
			if (this != &sp)
			{
				if (--(*_pcount) == 0)
				{
					delete _pcount;
					delete _ptr;
				}
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
			}
			return *this;
		}

引用计数为0时才能对_ptr进行释放,否则会发生内存泄漏。

++操作最终会被翻译为3条汇编指令。

namespace sp
{
	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr)
			:_ptr(ptr)
			,_pcount(new int(1))
			,_pmtx(new mutex)
		{}
		shared_ptr(shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pcount(sp._pcount)
			,_pmtx(sp._pmtx)
		{
			//++(*_pcount);
			add_ref_count();
		}
		void add_ref_count()
		{
			_pmtx.lock();
			++(*_pcount);
			_pmtx.unlock();
		}
		void release()
		{
			bool flag = true;
			_pmtx.lock();
			if (--(*_pcount) == 0 && _ptr)
			{
				cout << "delete: " << _ptr << endl;
				delete _ptr;
				_ptr = nullptr;
				delete _pcount;
				_pcount = nullptr;
				flag = true;
			}
			_pmtx.unlock();
			if (flag == true)
			{
				delete _pmtx;
				_ptrx = nullptr;
			}
		}
		//sp1=sp4
		shared_ptr<T>& operator=(shared_ptr<T>& sp)
		{
			if (this != &sp)
			{
				release();
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
			}
			return *this;
		}
		~shared_ptr()
		{
			release();
		}
	private:
		T* _ptr;
		int* _pcount;
		mutex _pmtx;
	};
}

shared_ptr:不能解决循环引用的问题

weak_ptr: 可以辅助shared_ptr解决循环引用的问题,严格来说weak_ptr不是智能指针。

template<class T>
class weak_ptr
{
public:
	weak_ptr() = default;
	weak_ptr(const sp::shared_ptr<T>& sp)
		:_ptr(sp.get_ptr())
	{}
	weak_ptr<T>& operator=(const shared_ptr<T>& sp)
	{
		_ptr = sp.get_ptr();
		return *this;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	T* get_ptr() const
	{
		return _ptr;
	}
private:
	T* _ptr;
};
struct ListNode
{
	int val;
	sp::shared_ptr<ListNode> _spnext;
	sp::shared_ptr<ListNode> _spprev;
	ListNode()
		:val(0)
		, _spnext(nullptr)
		, _spprev(nullptr)
	{}
	~ListNode()
	{
		cout << "~ListNode()" << endl;
	}
};
sp::shared_ptr<ListNode> spn1(new ListNode);
sp::shared_ptr<ListNode> spn2(new ListNode);
spn1->_spnext = spn2;
spn2->_spprev = spn1;

智能指针是RAII设计思想的体现

本质上RAII就是借助了构造函数和析构函数,构造函数和析构函数的特点都是自动调用。

使用RAII思想设计的锁管理守卫

template<class lock>
class LockGuard
{
public:
	LockGuard(Lock& lock)
		:_lk(lock)
	{
		_lk.lock();
	}
	~LockGuard()
	{
		cout << "解锁" << endl;
		_lk.unlock();
	}
private:
	Lock& _lk;
};

如何实现,创建出的类只能在堆上?

class HeapOnly
{
public:
	static HeapOnly* GetObj()
	{
		return new HeapOnly;
	}
	HeapOnly(const HeapOnly&) = delete;
private:
	HeapOnly()
	{}

};
shared_ptr<HeapOnly> sp1(HeapOnly::GetObj());
shared_ptr<HeapOnly> sp2(HeapOnly::GetObj());

如何实现,创建出的类只能在栈上?

class StackOnly
{
public:
	static StackOnly GetObj()
	{
		return StackOnly();//传值返回需要调用拷贝构造
	}
private:
	StackOnly() {}
	
};
StackOnly so = StackOnly::GetObj();
StackOnly* p = new StackOnly;//operator new+ 构造函数

构造函数私有化后,这个类就不能被继承了。

单例模式

简单的单例模式

懒汉模式:

class Singleton
{
public:
	static Singleton* GetInstance()
	{
        //sleep(1000);
        //_mtx.lock();
        if(_pinst==nullptr)
    {
        unique_lock<mutex> lock(_mtx);
		if (_pinst == nullptr)
		{
			_pinst = new Singleton;
		}
    }
        //_mtx.unlock();
		return _pinst;
	}
private:
	Singleton() {}
	Singleton(const Singleton& s) = delete;
	static Singleton* _pinst;
    static mutex _mtx;
};
Singleton* Singleton::_pinst = nullptr;
mutex Singleton::_mtx;

第一个if是为了防止对象已经创建好之后2,还需要每次加锁,造成锁的浪费

第二个if是防止非原子操作导致多个线程一起写

饿汉模式

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		return &_inst;
	}
	Singleton(const Singleton&) = delete;
private:
	Singleton()
	{}
	static Singleton _inst;
};

总结:

1.懒汉模式需要考虑线程安全和释放的问题,实现复杂而饿汉模式实现简单

2.懒汉模式是懒加载模式需要再初始化创建对象,不会影响程序启动,

饿汉模式程序启动时就创建实例化对象,会导致程序变慢

3.如何有多个单例类,假设有依赖关系(B依赖A)要求A单例先创建初始化,B单例在创建初始化,则不能用饿汉模式,饿汉模式无法保证创建初始化顺序,懒汉模式可以手动控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值