hiredis 多线程不安全,要想多线程使用就得维护一个对象池,使用起来比较麻烦
//redis.hpp
#include
#include
#include
#include
#include
#include
#include
using namespace std;
// typedef std::vector CharVector;
class RedisClient {
public:
RedisClient()
{
}
~RedisClient()
{
for (int i = 0; i < conn_num; ++i) {
if (conn_pool[i] != NULL) {
redisFree(conn_pool[i]);
conn_pool[i] = NULL;
}
}
delete[] conn_pool;
conn_flag.clear();
// if (conn_flag != NULL) {
// delete[] conn_flag;
// conn_flag = NULL;
// }
}
int init(std::string ip_, int port_, int conn_num_)
{
ip = ip_;
port = port_;
conn_num = conn_num_;
conn_pool = new redisContext*[conn_num];
if (conn_pool == NULL) {
return 1;
}
conn_flag.reserve(conn_num) ;
if (conn_flag.capacity() != conn_num) {
return 2;
}
for (int i = 0; i < conn_num; ++i) {
conn_pool[i] = redisConnect(ip.c_str(), port);
if (conn_pool[i] == NULL || conn_pool[i]->err) {
return 3;
}
conn_flag[i] = 0;
}
empty_num = conn_num;
current_conn = 0;
return 0;
}
bool isConnOk(redisContext* conn);
// bool Reconnect();
// bool Conn(const char* ip, int port = 6379);
// void Close();
// int checkError();
// size_t SetHValue(redisContext* conn,std::string& table, std::string& field, const char* value, size_t len);
// size_t SetHValue(redisContext* conn,std::string& table, std::string& field, std::string& value);
// int64_t INCR(redisContext* conn,std::string& table, std::string& field, int count);
// size_t QueryKeys(redisContext* conn,std::string& table, std::vector& vec);
// size_t QueryKeys(redisContext* conn,std::string& table, std::map& map);
// size_t Query(redisContext* conn,std::string& table, std::string& field, std::string& value);
// size_t Query(std::string & table, std::string & field, CharVector & value);
// size_t QueryCount(string& table);
// size_t SetHValue(const char * table, const char * field, const char * value, size_t len);
size_t Query(const char* table, const char* field, char** pValue );
// size_t QueryCount(redisContext* conn,const char* table);
// int64_t INCR(redisContext* conn,const char* table, const char* field, int count);
// CharVector buffer;
private:
void set_conn(int id){
if(conn_pool[id] !=NULL){
redisFree(conn_pool[id]);
}
conn_pool[id] = redisConnect(ip.c_str(), port);
if(conn_pool[id] == NULL || conn_pool[id]->err)
{
std::cout << "connect error!" << std::endl;
return;
}
std::cout << "reconnect" << std::endl;
}
redisContext* get_conn(int &out_id)
{
if (empty_num == 0) {
return NULL;
}
mtx.lock();
while (conn_flag[current_conn] != 0) {
current_conn = (current_conn + 1) % conn_num;
}
conn_flag[current_conn] = 1;
--empty_num;
out_id = current_conn;
current_conn = (current_conn + 1) % conn_num;
mtx.unlock();
return conn_pool[out_id];
}
void put_conn(int id)
{
if (id < conn_num && id >= 0) {
mtx.lock();
conn_flag[id] = 0;
++empty_num;
mtx.unlock();
}
return;
}
// redisContext* conn = nullptr;
// redisReply* getReply; // used for get
std::string ip;
int port;
int conn_num;
redisContext** conn_pool;
std::vector<int> conn_flag;
int empty_num;
int current_conn;
std::mutex mtx;
};
//redis.cpp
#include "redis.hpp"
#include
using namespace robin;
#define MAX_CONN_TIMES 10
#define DEBUG
bool RedisClient::isConnOk(redisContext* conn)
{
if (conn == nullptr)
return false;
// if (checkError() > 0)
// return false;
if (!(conn->flags & REDIS_CONNECTED)) {
return false;
}
bool ret = false;
redisReply* reply = static_cast<redisReply*>(redisCommand(conn, "PING"));
if (reply == nullptr)
return false;
if (reply->len > 0)
ret = true;
freeReplyObject(reply);
return ret;
}
// bool RedisClient::Reconnect()
// {
// this->Close();
// int n = 0;
// bool ret = Conn(_ip.c_str(), _port);
// while (ret == false && n < MAX_CONN_TIMES) {
// ret = Conn(_ip.c_str(), _port);
// n++;
// }
// return ret;
// }
// bool RedisClient::Conn(const char* ip, int port)
// {
// this->_ip = ip;
// this->_port = port;
// if (conn != nullptr)
// return 0;
// conn = redisConnect(ip, port);
// // struct timeval tm;
// // tm.tv_sec = 2;
// // tm.tv_sec = 0;
// // conn = redisConnectWithTimeout(ip, port, tm);
// if (conn->err) {
// printf("redis connection error:%s\n", conn->errstr);
// return false;
// }
// return true;
// }
// size_t RedisClient::SetHValue(redisContext* conn,std::string& table, std::string& field, const char* value, size_t len)
// {
// redisReply* reply = static_cast(
// redisCommand(conn, "HSET %b %b %b", table.c_str(), table.size(),
// field.c_str(),
// field.size(),
// value, len));
// if (reply == nullptr)
// return 0;
// size_t ret = 0;
// if (reply->type == REDIS_REPLY_INTEGER) {
// ret = reply->integer;
// }
// freeReplyObject(reply);
// return ret;
// }
// size_t RedisClient::SetHValue(redisContext* conn,std::string& table, std::string& field, std::string& value)
// {
// if (conn == nullptr)
// return -1;
// std::string cmd;
// std::stringstream stream;
// stream << "HSET " << table << " " << field << " " << value;
// cmd = stream.str();
// redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
// if (reply == nullptr)
// return 0;
// size_t ret = 0;
// if (reply->type == REDIS_REPLY_INTEGER) {
// ret = reply->integer;
// }
// freeReplyObject(reply);
// return ret;
// }
// int64_t RedisClient::INCR(redisContext* conn,const char* table, const char* field, int count)
// {
// if (conn == nullptr)
// return -1;
// std::string cmd = "";
// std::stringstream stream;
// stream << "hincrby " << table << " " << field << " " << count;
// cmd = stream.str();
// redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
// if (reply == nullptr)
// return 0;
// int64_t ret = reply->integer;
// freeReplyObject(reply);
// return ret;
// }
// int64_t RedisClient::INCR(redisContext* conn,std::string& table, std::string& field, int count)
// {
// return INCR(conn,table.c_str(), field.c_str(), count);
// }
// size_t RedisClient::QueryKeys(redisContext* conn,std::string& table, std::map& map)
// {
// std::string cmd = "";
// std::stringstream stream;
// stream << " HKEYS " << table;
// cmd = stream.str();
// redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
// size_t len = 0;
// if (reply == nullptr)
// return 0;
// for (size_t i = 0; i < reply->elements; i++) {
// redisReply* item = *(reply->element + i);
// uint32_t id = atoi(item->str);
// map.insert(std::pair(id, item->str));
// if (id > len)
// len = id;
// }
// freeReplyObject(reply);
// return len;
// }
// size_t RedisClient::QueryKeys(redisContext* conn,std::string& table, std::vector& vec)
// {
// std::string cmd = "";
// std::stringstream stream;
// stream << " HKEYS " << table;
// cmd = stream.str();
// redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
// if (reply == nullptr)
// return 0;
// size_t len = reply->elements;
// for (size_t i = 0; i < reply->elements; i++) {
// redisReply* item = *(reply->element + i);
// vec.push_back(item->str);
// // item->str;
// }
// freeReplyObject(reply);
// return len;
// }
// size_t RedisClient::QueryCount(redisContext* conn,const char* table)
// {
// std::string cmd = "";
// std::stringstream stream;
// stream << " HLEN " << table;
// cmd = stream.str();
// redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
// if (reply == nullptr)
// return 0;
// //_atoi64(char *)
// // char *end;
// // strtoll(reply->str, &end, 10);
// size_t len = reply->integer;
// freeReplyObject(reply);
// return len;
// }
// size_t RedisClient::QueryCount(string& table)
// {
// return QueryCount(table.c_str());
// }
// size_t RedisClient::Query(redisContext* conn,std::string& table, std::string& field, std::string& value)
// {
// std::string cmd = "";
// std::stringstream stream;
// stream << " HGET " << table << " " << field;
// cmd = stream.str();
// redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
// if (reply == nullptr)
// return 0;
// size_t len = reply->len;
// value = reply->str;
// freeReplyObject(reply);
// return len;
// }
// size_t RedisClient::Query(std::string& table, std::string& field, CharVector& value)
// {
// std::string cmd = "";
// std::stringstream stream;
// stream << " HGET " << table << " " << field;
// cmd = stream.str();
// redisReply* reply = static_cast(redisCommand(conn, cmd.c_str()));
// if (reply == nullptr)
// return 0;
// size_t len = reply->len;
// value.reserve(len);
// value.append(reply->str, len);
// freeReplyObject(reply);
// return len;
// }
size_t RedisClient::Query(const char* table, const char* field, char** pValue)
{
int current_conn = 0;
redisContext* conn = get_conn(current_conn);
#ifdef DEBUG
bool res = isConnOk(conn);
cout<<res<<endl;
if(!res){
set_conn(current_conn);
}
#endif
std::string cmd = "";
std::stringstream stream;
stream << " HGET " << table << " " << field;
cmd = stream.str();
// if (getReply)
// freeReplyObject(getReply);
redisReply* getReply = static_cast<redisReply*>(redisCommand(conn, cmd.c_str()));
if (getReply == nullptr)
return 0;
return 0;
*pValue = getReply->str;
size_t len = getReply->len;
put_conn(current_conn);
return len;
}
// void RedisClient::Close()
// {
// if (getReply != nullptr) {
// freeReplyObject(getReply);
// getReply = nullptr;
// }
// if (conn != nullptr) {
// redisFree(conn);
// conn = nullptr;
// }
// }
// int RedisClient::checkError()
// {
// if (conn->err == REDIS_ERR_IO || conn->err == REDIS_ERR_EOF) {
// return 1;
// }
// return 0;
// }
使用redis-plus-plus来操作redis更加的分布,redis类多线程安全,内部维护了一个连接池
demo
#include
#include
#include
#include
#include
extern "C" {
#include // for getopt on non-Windows platform
}
std::string host = "127.0.0.1";
int port = 6379;
std::string auth;
std::string cluster_node;
int cluster_port = 0;
bool benchmark = false;
int resp = 3;
int main(){
sw::redis::Optional<sw::redis::ConnectionOptions> opts;
if (!host.empty() && port > 0) {
sw::redis::ConnectionOptions tmp;
tmp.host = host;
tmp.port = port;
tmp.password = auth;
tmp.resp = resp;
opts = sw::redis::Optional<sw::redis::ConnectionOptions>(tmp);
}
if(opts.has_value()){
sw::redis::Redis redis(*opts);
redis.set("hello", "world");
std::string value;
auto stringopts = redis.get("hello2");
if(stringopts.has_value()){
value = *stringopts;
}
std::cout<<value<<std::endl;
}
}