最近写了一个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();
}