陈硕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());
    }
}

posted @ 2020-02-08 16:19  joeyzzz  阅读(436)  评论(0编辑  收藏  举报