最近写了一个hiredis的连接池,借鉴了HiRedis库封装,加了些日志,发现这个在ReleaseClient函数中构造shared_ptr时,没有指定delete。修改后在项目使用过程中发现执行一段时间后总是是卡死,使用的是boost库中的锁及其条件变量。
而日志系统中也用到了锁,添加日志调用时无序的。
连接池中用的锁用lock1表示,日志系统中用的锁用lock2表示
就会出现线程1调用锁的顺序为lock1->lock2,而线程2调用锁的顺序为lock2->lock1,造成死锁
将日志调用去掉后,没有出现卡死情况了
typedef std::shared_ptr<RedisClient> RedisClientPtr;class HiRedisPool
{
public:static HiRedisPool* getInstance(){static HiRedisPool instance;return &instance;}void init(const std::string& ip, int port, size_t maxCon);void getRedisClient(RedisClientPtr& redisClientPtr);void releaseClient(RedisClient *client_ptr);inline size_t size(){boost::lock_guard<boost::mutex> lock(_mutex);return _pool.size();}inline size_t used(){boost::lock_guard<boost::mutex> lock(_mutex);return _used;}private:HiRedisPool();HiRedisPool(const HiRedisPool& other);HiRedisPool& operator=(const HiRedisPool& other);private:std::string _ip;int _port;size_t _used;size_t _maxConnection;std::list<RedisClientPtr> _pool;boost::mutex _mutex;boost::condition_variable _cv;
};HiRedisPool::HiRedisPool()
{}void HiRedisPool::init(const std::string& ip, int port, size_t maxCon)
{boost::lock_guard<boost::mutex> lock(_mutex);_ip = ip;_port = port;_maxConnection = maxCon;_used = 0;
}void HiRedisPool::getRedisClient(RedisClientPtr& redisClientPtr)
{boost::unique_lock<boost::mutex> lock(_mutex);if (!_pool.empty()) {redisClientPtr = _pool.front();_pool.pop_front();} else if (_used < _maxConnection){++_used;redisClientPtr = std::shared_ptr<RedisClient>(new RedisClient(_ip, _port),std::bind(&HiRedisPool::releaseClient, this, std::placeholders::_1));} else {_cv.wait(lock, [this](){return !this->_pool.empty();});redisClientPtr = _pool.front();_pool.pop_front();}
}void HiRedisPool::releaseClient(RedisClient *client_ptr)
{{boost::lock_guard<boost::mutex> lock(_mutex);_pool.push_back(std::shared_ptr<RedisClient>(client_ptr,std::bind(&HiRedisPool::releaseClient, this, std::placeholders::_1)));}_cv.notify_one();}