用智能指针管理连接池(如数据库连接池、redis连接池),当智能指针离开作用域时,调用定制的删除器,删除器中调用指定的函数,并不是将连接断开,而是将连接放进一个容器中。当需要获取连接时,从连接池中获取一个空闲的连接。
目录
自定义删除器
scoped_ptr.h
#ifndef SCOPED_PTR_H_INCLUDED
#define SCOPED_PTR_H_INCLUDED
#include <iostream>
template <typename T>
class PoolFunction
{
public:
virtual T* get() = 0;
virtual bool release(T *) = 0;
virtual ~PoolFunction() {}
};
template<typename T>
struct PoolDeleter {
explicit PoolDeleter(PoolFunction<T> *pool = 0):m_pool(pool) {}
inline void operator()(T* ptr) const {
if (m_pool){
m_pool->release(ptr); //调用pool中方法
}
}
void setPool(PoolFunction<T> *pool){
m_pool = pool;
}
private:
PoolFunction<T> *m_pool;
};
#endif // SCOPED_PTR_H_INCLUDED
api_redis.h
以redis为例。以下只是举个例子,类RedisConn将hiredis中的api重新包装下即可。
#ifndef _API_REDIS_H_
#define _API_REDIS_H_
#include <vector>
#include <string>
#include <map>
#include <deque>
#include <stdint.h>
#include <hiredis/hiredis.h>
#include "scoped_ptr.h"
namespace redis
{
typedef struct conn_info_s
{
std::string host;
int port;
int db;
} conn_info_t;
class RedisConn {
private:
std::string m_host;
int m_port;
int m_db;
struct timeval m_timeout_tv;
redisContext* m_context;
public:
RedisConn(std::string& host, int port, int db = 0, int timeout_ms = 1000);
~RedisConn() { if(m_context != NULL) { redisFree(m_context); } }
/*
实现redis各种命令:CONNECT, HSET, HGET ....
此处省略
**/
};
class RedisPool :public PoolFunction<RedisConn> {
private:
std::deque<RedisConn *> m_conns; //调用删除器release的时候,将空闲连接存在deque中
std::mutex m_lock;
std::string m_host;
int m_port;
int m_db;
public:
RedisPool(const std::string& host, int port, int db = 0) : m_host(host), m_port(port), m_db(db) { };
RedisConn* get();
bool release(RedisConn* redis_conn);
};
};
typedef std::unique_ptr<redis::RedisConn, PoolDeleter<redis::RedisConn> > RedisConnUniquePtr;
api_redis.cpp
#include "api_redis.h"
#include <iostream>
using std::string;
using std::vector;
using std::map;
using std::cout;
using std::endl;
redis::RedisConn::RedisConn(string& host, int port, int db, int timeout_ms) : m_host(host), m_port(port), m_db(db), m_context(NULL) {
m_timeout_tv.tv_sec = timeout_ms/1000;
m_timeout_tv.tv_usec = (timeout_ms % 1000) * 1000;
}
/*
实现RedisConn的其他方法
*/
//get从连接池中获取一个空闲的连接,如果没有空闲的连接则新建一个连接。
redis::RedisConn* redis::RedisPool::get() {
RedisConn* conn = NULL;
if(true) {
std::unique_lock<std::mutex> autolock(m_lock);
if(!m_conns.empty()) {
conn = m_conns.front();
m_conns.pop_front();
std::cout << "get pop_front" <<endl;
return conn;
}
}
std::cout << "get new" <<endl;
conn = new RedisConn(m_host, m_port, m_db);
return conn;
}
//删除器中调用了pool->release方法
bool redis::RedisPool::release(RedisConn* redis_conn) {
if(redis_conn == NULL) {
return true;
}
std::unique_lock<std::mutex> autolock(m_lock);
m_conns.push_back(redis_conn);
std::cout << "release" <<endl;
return true;
}
main.cpp
使用实例
在实际使用中,可将g_redis_pool 和g_redis_conn_delter设置为全局变量。那么在业务的各种线程中可通过一行代码来从redis连接池中获取redis连接,作用域结束后将调用删除器将连接放入空闲连接池:
RedisConnUniquePtr conn_Redis(g_redis_pool->get(), g_redis_conn_delter);
int main()
{
redis::conn_info_t redisConf;
redisConf.host = "127.0.0.1";
redisConf.port = "6379";
redis::RedisPool * g_redis_pool = new redis::RedisPool(redisConf.host, redisConf.port);//new一个pool
PoolDeleter<redis::RedisConn> g_redis_conn_delter;//删除器
g_redis_conn_delter.setPool(g_redis_pool);//设置pool
{
std::unique_ptr<redis::RedisConn, PoolDeleter<redis::RedisConn> > conn_Redis(g_redis_pool->get(), g_redis_conn_delter);
}
{
RedisConnUniquePtr conn_Redis(g_redis_pool->get(), g_redis_conn_delter);
}
{
RedisConnUniquePtr conn_Redis(g_redis_pool->get(), g_redis_conn_delter);
}
return 0
}