目录
类的线程安全
实现线程安全
构造函数在多线程中的安全性
#include <iostream>
class Observable;
class Observer {
public:
virtual void update() = 0; // 纯虚函数,用于接收更新通知
};
class Foo : public Observer {
public:
// 错误:在构造函数中直接注册 `this`,会造成线程不安全
Foo(Observable* s) {
s->registerObserver(this); // 将 `this` 立即注册到 `Observable`
std::cout << "Foo 对象已构造并注册\n";
}
virtual void update() override {
std::cout << "Foo 收到了更新通知\n";
}
private:
int someData = 0; // 假设这是一个重要的初始化数据
};
class Observable {
public:
void registerObserver(Observer* o) {
observer_ = o;
std::cout << "观察者已注册\n";
}
void notifyObservers() {
if (observer_) {
observer_->update();
}
}
private:
Observer* observer_ = nullptr;
};
int main() {
Observable observable;
Foo* foo = new Foo(&observable); // 在构造函数中注册 `this`
observable.notifyObservers(); // 通知观察者,可能在对象未完全初始化时访问
delete foo;
return 0;
}
#include <iostream>
class Observable;
class Observer {
public:
virtual void update() = 0; // 纯虚函数,用于接收更新通知
};
class Foo : public Observer {
public:
Foo() {
// 在构造函数中仅初始化对象,不进行任何注册操作
std::cout << "Foo 对象已构造\n";
}
// 观察者更新接口实现
virtual void update() override {
std::cout << "Foo 收到了更新通知\n";
}
// 提供一个专门的函数用于在构造后进行注册
void observe(Observable* s);
private:
// 内部成员变量
int someData = 0;
};
class Observable {
public:
void registerObserver(Observer* o) {
observer_ = o;
std::cout << "观察者已注册\n";
}
void notifyObservers() {
if (observer_) {
observer_->update();
}
}
private:
Observer* observer_ = nullptr;
};
// Foo类的observe方法实现,确保注册操作在构造完成后进行
void Foo::observe(Observable* s) {
s->registerObserver(this); // 仅在对象构造后再注册
}
int main() {
Observable observable;
Foo* foo = new Foo(); // 构造对象
foo->observe(&observable); // 构造完成后进行注册
observable.notifyObservers(); // 通知观察者进行更新
delete foo;
return 0;
}
析构函数多线程环境的安全
多线程环境下的析构比单线程析构是更为复杂的,主要原因是因为其涉及到资源的竞争条件。如果在多线程环境下确保线程安全,析构函数必须小心处理对象的状态,同时与其他线程保持同步。
#include <iostream>
#include <thread>
#include <mutex>
class Foo {
public:
~Foo() {
std::lock_guard<std::mutex> lock(mutex_); // 互斥锁保护析构函数
std::cout << "Foo 被销毁\n";
}
void update() {
std::lock_guard<std::mutex> lock(mutex_); // 互斥锁保护更新函数
std::cout << "Foo 更新\n";
}
private:
std::mutex mutex_;
};
Foo* x = nullptr; // 全局对象指针,多个线程共享
void threadA() {
delete x; // 线程A销毁对象
x = nullptr; // 设置 x 为 NULL
}
void threadB() {
if (x) { // 线程B检查 x 是否为NULL
x->update(); // 如果 x 不为NULL,则调用 update()
} else {
std::cout << "x 是空指针\n";
}
}
int main() {
x = new Foo(); // 初始化全局对象指针
std::thread t1(threadA); // 线程A销毁对象
std::thread t2(threadB); // 线程B调用 update()
t1.join();
t2.join();
return 0;
}
智能指针实现多线程安全
#include <iostream>
#include <memory>
#include <thread>
std::shared_ptr<int> globalPtr; // 全局 shared_ptr
void threadFunc() {
std::shared_ptr<int> localPtr = globalPtr; // 安全地共享对象
if (localPtr) {
std::cout << "Thread accessing: " << *localPtr << std::endl;
}
}
int main() {
globalPtr = std::make_shared<int>(42); // 初始化 shared_ptr
std::thread t1(threadFunc);
std::thread t2(threadFunc);
t1.join();
t2.join();
globalPtr.reset(); // 主线程释放对象,其他线程仍然安全使用
return 0;
}
shared_ptr 非完全线程安全
#include <iostream>
#include <memory>
#include <thread>
#include <mutex>
std::shared_ptr<int> globalPtr;
std::mutex mtx;
void readSharedPtr() {
std::lock_guard<std::mutex> lock(mtx);
if (globalPtr) {
std::cout << "Reading: " << *globalPtr << std::endl;
}
}
void writeSharedPtr(int value) {
std::lock_guard<std::mutex> lock(mtx);
if (globalPtr) {
*globalPtr = value;
std::cout << "Writing: " << value << std::endl;
}
}
int main() {
globalPtr = std::make_shared<int>(42);
std::thread t1(readSharedPtr);
std::thread t2(writeSharedPtr, 100);
t1.join();
t2.join();
return 0;
}
shared_ptr可能导致对象生命周期延长
shared_ptr是引用计数的智能指针,引用计数决定的对象的生命周期,但是使用过程中如果有一个指向该对象的指针没有析构,这样就会导致该对象永远不会被释放。
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <iostream>
#include <vector>
#include <memory>
#include <boost/bind.hpp>
#include <boost/function.hpp>
class Observer {
public:
Observer(int id) : id_(id) {
std::cout << "Observer " << id_ << " created." << std::endl;
}
~Observer() {
std::cout << "Observer " << id_ << " destroyed." << std::endl;
}
void onNotify() {
std::cout << "Observer " << id_ << " notified." << std::endl;
}
private:
int id_;
};
class Subject {
public:
void registerObserver(std::shared_ptr<Observer> obs) {
observers_.push_back(obs); // 使用 shared_ptr 存储观察者
}
void unregisterObserver(std::shared_ptr<Observer> obs) {
observers_.erase(std::remove(observers_.begin(), observers_.end(), obs), observers_.end());
}
void notifyAll() {
for (auto& obs : observers_) {
if (obs) {
obs->onNotify();
}
}
}
private:
std::vector<std::shared_ptr<Observer>> observers_;
};
void delayedCallback(boost::function<void()> func) {
std::cout << "Callback will be called after delay..." << std::endl;
func(); // 延迟回调调用
}
int main() {
Subject subject;
// 创建两个观察者并注册
std::shared_ptr<Observer> observer1(new Observer(1));
std::shared_ptr<Observer> observer2(new Observer(2));
subject.registerObserver(observer1);
subject.registerObserver(observer2);
// 这里的 boost::bind 使 shared_ptr 的引用计数增加
boost::function<void()> func = boost::bind(&Observer::onNotify, observer1);
// 执行延迟回调
delayedCallback(func);
// 移除观察者
subject.unregisterObserver(observer1);
subject.unregisterObserver(observer2);
// 通知所有观察者
subject.notifyAll();
// 注意:observer1 的引用计数不会为 0,因为 boost::function 持有了它的 shared_ptr 副本
return 0;
}
const引用可以减少传递shared_ptr开销
void onMessage(const std::string& msg) {
std::shared_ptr<Foo> pFoo(new Foo(msg)); // 创建 shared_ptr,持有 Foo 实例
if (validate(pFoo)) { // 通过 const 引用传递 shared_ptr
save(pFoo); // 通过 const 引用传递 shared_ptr
}
}
shared_ptr 智能指针块模块的优点
析构所在线程问题分析
在多线程环境下,最后拥有对象的线程不一定是初始线程,所以需要该处对最后析构线程进行分析。
RAII的使用
涉及到资源管理必然不可以绕开RAII,RAII的核心思想就是在对象构建的时候同时获取资源,并在对象销毁的时候同时释放资源。
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <queue>
#include <mutex>
#include <condition_variable>
// 资源类,构造时分配资源,析构时释放资源
class Resource {
public:
Resource() {
std::cout << "资源已获取\n";
}
~Resource() {
std::cout << "资源已释放\n";
}
};
// 模拟处理资源的函数
void processResource(std::shared_ptr<Resource> res) {
std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟处理延迟
std::cout << "正在处理资源\n";
}
// 阻塞队列类,用于在线程间传递资源
template <typename T>
class BlockingQueue {
public:
// 向队列中添加资源
void push(T item) {
std::lock_guard<std::mutex> lock(mtx);
queue.push(item);
cond.notify_one(); // 唤醒等待的线程
}
// 从队列中取出资源
T pop() {
std::unique_lock<std::mutex> lock(mtx);
cond.wait(lock, [this]() { return !queue.empty(); }); // 等待直到队列非空
T item = queue.front();
queue.pop();
return item;
}
private:
std::queue<T> queue;
std::mutex mtx;
std::condition_variable cond;
};
// 专用线程,处理资源的析构
void workerThread(BlockingQueue<std::shared_ptr<Resource>>& queue) {
while (true) {
auto res = queue.pop(); // 从队列中获取资源
processResource(res); // 处理资源
// 资源会在这里自动析构
}
}
int main() {
// 创建阻塞队列和专用线程
BlockingQueue<std::shared_ptr<Resource>> queue;
std::thread worker(workerThread, std::ref(queue));
// 主线程分配资源并将其传递给专用线程
{
auto res = std::make_shared<Resource>(); // 使用shared_ptr分配资源
queue.push(res); // 将资源传递给队列,worker线程将接管资源
}
worker.join(); // 等待专用线程结束
return 0;
}
enable_shared_from_this 使用场景分析
问题分析
当使用智能指针来管理对象的生命周期,智能指针会自动管理对象资源的分配和释放,从而避免内存泄漏。但是在某些情况下,智能指针所管理的对象需要在其成员函数内存获取一个指向自身的shared_ptr。在这种情况下如果直接使用this指针操作,可能会导致严重的生命周期管理的问题,尤其在回调函数以及多线程环境下,该问题会更明显,结合下面的事例详细理解。
#include <iostream>
#include <memory>
#include <functional>
class Manager : public std::enable_shared_from_this<Manager> {
public:
// 模拟删除资源的函数
void deleteResource() {
std::cout << "Manager: Deleting resource\n";
}
// 返回当前对象的shared_ptr
std::shared_ptr<Manager> getSharedManager() {
return shared_from_this();
}
};
class Resource {
public:
Resource(std::shared_ptr<Manager> mgr) : manager(mgr) {
std::cout << "Resource Created\n";
// 绑定析构时的回调函数,调用Manager的deleteResource函数
destructorCallback = std::bind(&Manager::deleteResource, manager);
}
~Resource() {
std::cout << "Resource Destroyed\n";
// 调用析构回调,通知Manager
destructorCallback();
}
private:
std::shared_ptr<Manager> manager;
std::function<void()> destructorCallback;
};
int main() {
// 创建一个Manager对象并使用shared_ptr管理其生命周期
std::shared_ptr<Manager> manager = std::make_shared<Manager>();
{
// 创建Resource对象,并将Manager传递给它
std::shared_ptr<Resource> resource = std::make_shared<Resource>(manager);
} // Resource在此作用域结束时被销毁,其析构函数被调用
std::cout << "End of main\n";
return 0;
}
enable_shared_from_this确保对象安全
解决上述问题,则是通过C++中提供的一个enable_shared_from_this机制来实现,其是一个模版基类,允许类的实例从其成员函数中安全的获取shared_ptr执行自身,最终实现该对象的生命周期始终是由shared_ptr来控制的。
#include <iostream>
#include <memory>
class Manager : public std::enable_shared_from_this<Manager> {
public:
Manager() {
std::cout << "Manager Created\n";
}
~Manager() {
std::cout << "Manager Destroyed\n";
}
// 返回自身的 shared_ptr
std::shared_ptr<Manager> getSharedPtr() {
return shared_from_this();
}
void performTask() {
// 在成员函数内部获取 shared_ptr
auto sharedManager = shared_from_this();
std::cout << "Performing task with shared_ptr\n";
// 在这里 shared_ptr 的引用计数不会变成 0,因为还有其他地方持有它
}
};
int main() {
// Step 1: 创建一个 shared_ptr 管理 Manager 对象
std::shared_ptr<Manager> manager1 = std::make_shared<Manager>();
std::cout << "Reference Count after creation: " << manager1.use_count() << "\n"; // 引用计数为 1
// Step 2: 调用成员函数,获取 shared_ptr
manager1->performTask();
std::cout << "Reference Count after performTask: " << manager1.use_count() << "\n"; // 引用计数为 1,因为没有新增外部持有者
// Step 3: 在外部再获取一个 shared_ptr
std::shared_ptr<Manager> manager2 = manager1->getSharedPtr();
std::cout << "Reference Count after getSharedPtr: " << manager1.use_count() << "\n"; // 引用计数为 2
// Step 4: 销毁 manager1
manager1.reset();
std::cout << "Reference Count after resetting manager1: " << manager2.use_count() << "\n"; // 引用计数为 1
// Step 5: 销毁 manager2
manager2.reset();
std::cout << "All shared_ptrs destroyed\n";
return 0;
}
weak_ptr 和 shared_ptr 结合 Bind的弱回调机制(重点解决方案)
弱回调机制的实现
#include <iostream>
#include <memory>
#include <vector>
// 前置声明 Manager 类
class Manager;
// Worker 类负责执行任务,并在任务完成时通知 Manager
class Worker {
public:
// 构造函数中传入 Manager 的 weak_ptr
Worker(std::weak_ptr<Manager> manager);
~Worker();
// 执行任务
void doWork();
private:
// 使用 weak_ptr 避免循环引用
std::weak_ptr<Manager> manager_;
// 通知 Manager 任务已完成
void notifyManager();
};
// Manager 类负责管理 Worker
class Manager : public std::enable_shared_from_this<Manager> {
public:
Manager() {
std::cout << "Manager Created\n";
}
~Manager() {
std::cout << "Manager Destroyed\n";
}
// 注册 worker 完成任务的回调函数
void registerWorker() {
auto worker = std::make_shared<Worker>(shared_from_this());
workers_.push_back(worker);
worker->doWork();
}
void onTaskComplete() {
std::cout << "Manager received task completion notification\n";
}
private:
std::vector<std::shared_ptr<Worker>> workers_;
};
// 完整定义 Worker 类的方法
Worker::Worker(std::weak_ptr<Manager> manager)
: manager_(manager) {
std::cout << "Worker Created\n";
}
Worker::~Worker() {
std::cout << "Worker Destroyed\n";
}
void Worker::doWork() {
std::cout << "Worker is working...\n";
// 模拟任务完成后通知 Manager
notifyManager();
}
void Worker::notifyManager() {
if (auto manager = manager_.lock()) {
// manager 有效时通知
manager->onTaskComplete();
} else {
// 如果 Manager 已销毁,通知失败
std::cout << "Manager is no longer available\n";
}
}
int main() {
{
// 创建一个 Manager 对象并用 shared_ptr 管理
auto manager = std::make_shared<Manager>();
// 注册 Worker 并执行任务
manager->registerWorker();
std::cout << "Manager still exists\n";
}
// 当 Manager 销毁后,Worker 再次尝试访问 Manager 将失败
std::cout << "End of main\n";
return 0;
}