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.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章