多线程在访问共享对象时存在安全问题:某线程在访问共享对象时,共享对象可能已经被其它线程析构了,此时访问的共享对象是空的,造成线程的安全问题。
#include <iostream>
#include <memory>
#include <thread>
using namespace std;
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void testA() { cout << "testA()" << endl; }
};
void handler(A *q)
{
std::this_thread::sleep_for(std::chrono::seconds(2)); // 当前线程睡眠2s
// q在访问A对象的时,对象A可能已经被析构
q->testA();
}
int main()
{
A *p = new A();
thread t(handler, p);
delete p; // 主线程析构p对象
// 阻塞等待子线程结束
t.join();
return 0;
}
- 以上代码中,使用裸指针
p
指向对象A
,并启动线程t
,其中A
作为线程函数的参数,线程函数睡眠2s
,期间主线程可能已经析构了p
指针管理的对象A
,故子线程在访问A
对象时,存在安全问题。 - 可以利用智能指针来解决多线程访问共享对象时的安全问题。(定义对象时用强智能指针;引用对象的地方使用弱智能指针)
#include <iostream>
#include <memory>
#include <thread>
using namespace std;
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void testA() { cout << "testA()" << endl; }
};
// void handler(A *q)
void handler(weak_ptr<A> pw) // 弱智能指针会引起对象的引用计数改变!
{
// std::this_thread::sleep_for(std::chrono::seconds(2));
shared_ptr<A> sp = pw.lock();
if (sp != nullptr) // 检测共享对象是否存活
{
sp->testA();
}
else
{
cout << "A 对象已经析构,不能再访问.." << endl;
}
}
int main()
{
// A *p = new A();
shared_ptr<A> p(new A());
thread t(handler, weak_ptr<A>(p));
t.detach(); // 分离线程
std::this_thread::sleep_for(std::chrono::seconds(2)); // 主线程睡眠2s
return 0;
}
- 以上代码中,基于智能指针判断共享对象是否存活,解决了多线程访问共享对象时的安全问题。