陈硕Linux多线程服务端编程读书笔记 —— 第一章 线程安全的对象生命周期管理
muduo书第一章的思维导图(新窗口打开可以看大图)
线程安全的对象析构和回调(使用shared_ptr和weak_ptr)
注释是英文的(工地英语…)
StockFactory.h
// in multi-thread environment, there maybe a race condition
// an object's destruction is difficult to handle for complex cases
// a good news is that a smart pointer named "shared_ptr" provides ability to release the resources automatically
#ifndef MUDUO_STOCKFACOTRY_H
#define MUDUO_STOCKFACOTRY_H
#include "Mutex.h"
#include <boost/core/noncopyable.hpp>
#include <map>
#include <memory>
#include <functional>
class Stock
{
public:
Stock(const std::string &key);
std::string
Key() const;
private:
std::string key_;
};
class StockFactory1 : public boost::noncopyable
{
public:
std::shared_ptr<Stock> get(const std::string &key);
private:
mutable MutexLock mutex_;
std::map<std::string, std::shared_ptr<Stock>> stocks_;
};
class StockFactory2 : public boost::noncopyable
{
public:
std::shared_ptr<Stock> get(const std::string &key);
private:
mutable MutexLock mutex_;
std::map<std::string, std::weak_ptr<Stock>> stocks_;
};
class StockFactory3 : public boost::noncopyable
{
public:
std::shared_ptr<Stock> get(const std::string &key);
private:
mutable MutexLock mutex_;
std::map<std::string, std::weak_ptr<Stock>> stocks_;
void deleteStock(Stock *stock);
};
class StockFactory4 : public boost::noncopyable, std::enable_shared_from_this<StockFactory4>
{
public:
std::shared_ptr<Stock> get(const std::string &key);
private:
mutable MutexLock mutex_;
std::map<std::string, std::weak_ptr<Stock>> stocks_;
void deleteStock(Stock *stock);
};
class StockFactory5 : public boost::noncopyable, std::enable_shared_from_this<StockFactory5>
{
public:
std::shared_ptr<Stock> get(const std::string &key);
private:
mutable MutexLock mutex_;
std::map<std::string, std::weak_ptr<Stock>> stocks_;
static void weakDeleteCallback(const std::weak_ptr<StockFactory5> &wkFactory, Stock *stock);
void removeStock(Stock *stock);
};
#endif //MUDUO_STOCKFACOTRY_H
StockFactory.cpp
#include "StockFacotry.h"
#include "Mutex.h"
Stock::Stock(const std::string &key) : key_(key){
}
std::string Stock::Key() const
{
return key_;
}
// error, the memory managed by shared_ptr may never be released
std::shared_ptr<Stock> StockFactory1::get(const std::string &key)
{
MutexLockGuard lock(mutex_);
auto pos = stocks_.find(key);
if(pos != stocks_.end())
{
return pos->second;
} else
{
stocks_[key] = std::shared_ptr<Stock>(new Stock(key));
return stocks_[key];
}
}
// not that good, the map may contain to many weak_ptr entities.
// stocks_.size() equals the number of all objects including the released ones.
std::shared_ptr <Stock> StockFactory2::get(const std::string &key) {
std::shared_ptr<Stock> pStock;
MutexLockGuard lock(mutex_);
std::weak_ptr<Stock> &wpStock = stocks_[key];
pStock = wpStock.lock();
if(!pStock) // the resource is released in other thread or never exists
{
pStock.reset(new Stock(key));
wpStock = pStock;
}
return pStock;
}
std::shared_ptr <Stock> StockFactory3::get(const std::string &key) {
std::shared_ptr<Stock> pStock;
MutexLockGuard lock(mutex_);
std::weak_ptr<Stock> &wpStock = stocks_[key];
pStock = wpStock.lock();
if(!pStock) // if the resource is released in other thread or never exists
{
// potential risk, this pointer copy is exposed to multi-thread environment in lambda function
// if StockFactory object is destructing in Thread A while Thread B call this function
// there maybe a race condition which leads to core dump
// NOTE for std::bind: this pointer is needed when bind a member function
pStock.reset(new Stock(key), std::bind(&StockFactory3::deleteStock, this, std::placeholders::_1));
wpStock = pStock;
}
return pStock;
}
void StockFactory3::deleteStock(Stock *stock) {
if(stock)
{
MutexLockGuard lock(mutex_);
stocks_.erase(stock->Key());
}
delete stock; //???
}
std::shared_ptr<Stock> StockFactory4::get(const std::string &key)
{
std::shared_ptr<Stock> pStock;
MutexLockGuard lock(mutex_);
std::weak_ptr<Stock> &wpStock = stocks_[key];
pStock = wpStock.lock();
if(!pStock)
{
// the deleteStock function owns a copy of shared_ptr of this, which avoid the race condition
// HOWEVER, a extra copy of shared_ptr in function object may prolong the life of StockFactory by accident
pStock.reset(new Stock(key), std::bind(&StockFactory4::deleteStock, shared_from_this(), std::placeholders::_1));
}
return std::shared_ptr<Stock>();
}
void StockFactory4::deleteStock(Stock *stock) {
if(stock)
{
MutexLockGuard lock(mutex_);
stocks_.erase(stock->Key());
}
delete stock; //???
}
std::shared_ptr<Stock> StockFactory5::get(const std::string &key) {
std::shared_ptr<Stock> pStock;
MutexLockGuard lock(mutex_);
std::weak_ptr<Stock> &wpStock = stocks_[key];
pStock = wpStock.lock();
if(!pStock) // / the resource is released in other thread or never exists
{
pStock.reset(new Stock(key), std::bind(&StockFactory5::weakDeleteCallback, std::weak_ptr<StockFactory5>(shared_from_this()), std::placeholders::_1));
}
}
// awesome!!!
// call a member function in a static function via shard_ptr, which requires the object exists in fact
void StockFactory5::weakDeleteCallback(const std::weak_ptr<StockFactory5> &wkFactory, Stock *stock)
{
std::shared_ptr<StockFactory5> pFactory = wkFactory.lock();
if(pFactory)
{
pFactory->removeStock(stock);
}
delete stock;
}
void StockFactory5::removeStock(Stock *stock) {
if(stock)
{
MutexLockGuard lock(mutex_);
stocks_.erase(stock->Key());
}
}