C++多线程中访问共享对象错误场景以及使用shared_ptr和weak_ptr强弱指针设计解决方案

子线程访问被主线程delete掉的共享对象

class A{
public:
    A(int val = 100){ std::cout<<"A()"<<std::endl; ptr_ = new int; *ptr_ = val; }
    ~A() { std::cout<<" ~A()"<<std::endl; }
	void show(){ cout<<"*ptr_ = "<<*ptr_<<endl; }
private:
	int *ptr_;
};

void ThreadFunction(A *p){
	std::this_thread::sleep_for(std::chrono::seconds(3));
	//睡眠保证主线程将共享对象p析构掉
	p->show();
	//子线程中访问已经被主线程析构掉的对象的方法
}

int main(){
	A *p = new A(9999999);
	thread t1(ThreadFunction,p);

	delete p;
	t1.join();
	return 0;
}

上面的代码很简单,也很好理解,执行结果如下(不同平台结果可能不同,但是结果最终肯定是意料之外的):

A()
~A()
段错误 (核心已转储)

利用weak_ptr能否提升为强指针的特点来判断、检查共享对象是否还存在:

class A{
public:
    A(int val = 100){ cout<<"A()"<<endl; ptr_ = new int; *ptr_ = val; }
    ~A() { cout<<" ~A()"<<endl; }
	void show(){ cout<<"*ptr_ = "<<*ptr_<<endl; }
private:
	int *ptr_;
};

void ThreadFunction(weak_ptr<A> p){
	std::this_thread::sleep_for(std::chrono::seconds(3));

	shared_ptr<A> ptr = p.lock();
	if(ptr != nullptr){ 
		cout<<"Object still exists!!!"<<endl;
		ptr->show();
	}else{
		cout<<"shared object has been deleted!!!"<<endl;
	}
	
}

int main(){
	{
		shared_ptr<A> ptr (new A(8888));
		thread t1(ThreadFunction,weak_ptr<A>(ptr));
		t1.detach();
	}//出作用域 ptr资源释放,共享对象不存在
	std::this_thread::sleep_for(std::chrono::seconds(10));	
	return 0;
}

执行结果:

A()
 ~A()
shared object has been deleted!!!

总结:

  1. 如果共享对象存在,弱智能指针就可以成功提升为强智能指针,就可以用提升后的指针访问共享资源;
  2. 如果共享对象不存在,我们无法将弱智能指针提升,就不能去访问共享对象;
  3. 关键点:lock()方法返回值是否为nullptr.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章