最近待业,闲的蛋疼,发现C++下连mysql连接池这么基础的东西都没用过,身为一名计算机毕业生,深感愧疚,遂生一想法,写个或者找个连接池,以增强本人垃圾一样的专业修养。
没想到写出来第一版就存在内存管理问题导致的coredump,查了半天,发现是调用了空指针的成员函数,彻底晕倒,其间为了调试gdb core中bt出来的libmysqlclient.so的mysql_real_connect调用,我下了mysql的5.5.31源代码来编了若干遍,想编个debug版调试最后也是没有成功。发现问题还是看网上帖子讲segfault11这种问题多半都是空指针搞的,反过头加了些指针的打印语句才意识到低级的错误,后来debug过程中还发现了更低级的逻辑错误,略去不表,还是自己太菜,连个空指针这个白痴的内存问题都不预先防范,搞得一个300+行的东西,弄了三天才算稳定了,大大的罪过,浪费自己和社会的生产力。
过程中想到自己既然写不好,干脆找个好用的,结果发现了个libzdb,支持好些个开源db的连接池,随便下了个破代码测了一下,也没仔细搞,debug中参考了一下它的源码,还算是有点启发。
目前这个源码用valgrind自己测,有74KB左右的内存泄露,明白人能改改的话最好,作为一个菜鸟我只能帮自己到这了,当然这个泄露不会随时间线性的增长,这个我还是测过了的,有人能用到生产环境的话,麻烦给我提点改进意见,72小时的作品,太经不起考验了,目前本机上只能支持最多 152条连接,设成153就会报连接失败,牛逼的前辈们狠狠的批这份代码好了,自己也感觉自己水平太残废了,不知道是mysql设置还是系统设置的问题,总之无论是建议还是问题尽管扔过来吧,作为一个傻逼二货我照单全收。
上代码
去Github搞代码看这里 https://github.com/githcx/xPool
pool.h (1 in 3)
#include <mysql.h>
#include <stdio.h>
#include <string.h>
#include <map>
#include <vector>
#include <string>
#include <iostream>
#include <pthread.h>
using std::string;
using std::vector;
class Connection;
class some{
public:
some(){}
Connection * first;
bool second;
};
class Pool{
public:
static int initPool(string host,string user,string pass,string dbname,int poolSize);
static void destroyPool();
static Connection* getConnection();
static int releaseConnection(Connection*);
static void lock();
static void unlock();
static void locke();
static void unlocke();
static void locki();
static void unlocki();
static void lockl();
static void unlockl();
private:
static pthread_mutex_t mutex;
static pthread_mutex_t execmutex;
static pthread_mutex_t initmutex;
static pthread_mutex_t logmutex;
static Pool* pool_;
private:
some* vec; // need an instance to init
public:
static string host_ ;
static string user_ ;
static string pass_ ;
static string dbname_;
static int poolSize_ ;
public:
Pool(string host,string user,string pass,string dbname,int poolSize);
virtual ~Pool();
};
class QueryResult;
class Connection{
public:
Connection(string host,string user,string pass,string dbname);
virtual ~Connection();
QueryResult executeQuery(string statement);
private:
// MYSQL代表了一条TCP连接
MYSQL* conn;
};
class QueryResult{
public:
int getRowCount(){return string_table.size();}
int getColumnCount(){return string_table[0].size();};
string getElement(int row,int column){return string_table[row][column];}
void addRow(const vector<string>& row){string_table.push_back(row);}
private:
vector<vector<string> > string_table;
};
pool.h (2 in 3)
#include "pool.h"
#include <stdlib.h>
// for DEBUG
using std::cout;
using std::endl;
// static field init
string Pool::host_ = "";
string Pool::user_ = "";
string Pool::pass_ = "";
string Pool::dbname_ = "";
int Pool::poolSize_ = 0;
Pool* Pool::pool_ = NULL;
pthread_mutex_t Pool::mutex;
pthread_mutex_t Pool::execmutex;
pthread_mutex_t Pool::initmutex;
pthread_mutex_t Pool::logmutex;
void Pool::lock(){
pthread_mutex_lock(&mutex);
}
void Pool::unlock(){
pthread_mutex_unlock(&mutex);
}
void Pool::locke(){
pthread_mutex_lock(&execmutex);
}
void Pool::unlocke(){
pthread_mutex_unlock(&execmutex);
}
void Pool::locki(){
pthread_mutex_lock(&initmutex);
}
void Pool::unlocki(){
pthread_mutex_unlock(&initmutex);
}
void Pool::lockl(){
pthread_mutex_lock(&logmutex);
}
void Pool::unlockl(){
pthread_mutex_unlock(&logmutex);
}
Pool::Pool(string host,string user,string pass,string dbname,int poolSize){
vec = new some[Pool::poolSize_];
for(int i=0; i<poolSize_; i++){
Connection* conn = new Connection(Pool::host_,Pool::user_,Pool::pass_,Pool::dbname_);
//std::cout << conn << std::endl;
//std::cout << host << " " << user << " " << pass << " " << dbname << " " << poolSize << std::endl;
if(!conn){
cout << "xPool: new Connection Operation failed" << endl;
exit(-1);
}
vec[i].first = conn;
vec[i].second = false;
}
}
Pool::~Pool(){
for(int i=0;i<poolSize_;i++){
delete vec[i].first;
}
delete[] vec;
//mysql_library_end();
}
int Pool::initPool(string host,string user,string pass,string dbname,int poolSize){
host_ = host;
user_ = user;
pass_ = pass;
dbname_ = dbname;
poolSize_ = poolSize;
return 0;
}
void Pool::destroyPool(){
if(pool_){
delete pool_;
pool_ = NULL;
}
}
Connection* Pool::getConnection(){
// init pool, open connections
Pool::locki();
if(pool_ == NULL){
pthread_mutex_init(&mutex,0);
pthread_mutex_init(&execmutex,0);
//mysql_library_init(0,NULL,NULL);
pool_ = new Pool(host_,user_,pass_,dbname_,poolSize_);
}
Pool::unlocki();
//get connection operation
Connection* ret = NULL;
while(true){
Pool::lock();
bool flag = false;
for(int i=0;i<poolSize_;i++){
if(pool_->vec[i].second == false){
pool_->vec[i].second = true;
ret = pool_->vec[i].first;
flag = true;
break;
}
}
if(flag == true){
Pool::unlock();
break;
}
else{
//cout << "wait" << endl;
Pool::unlock();
usleep(1000);
continue;
}
}
return ret;
}
int Pool::releaseConnection(Connection* conn){
lock();
for(int i=0;i<poolSize_;i++){
if(pool_->vec[i].first == conn ){
pool_->vec[i].second = false;
break;
}
}
unlock();
return 1;
}
Connection::Connection(string host,string user,string pass,string dbname){
static int connectionCount = 0;
//cout << "C#:" << connectionCount++ << endl;
// 初始化连接
conn = mysql_init(NULL);
//cout << "conn:" << conn << endl;
// 执行物理的tcp连接动作,完成三次握手
if (!mysql_real_connect(conn,"localhost", "root", "jiqim1ma", "hcx",0,NULL,0)){
printf( "xPool: Error connecting to database: %s\n",mysql_error(conn));
exit(-1);
}
else{
}
}
Connection::~Connection(){
//mysql_thread_end();
// 关闭TCP连接,四次挥手
mysql_close(conn);
}
QueryResult Connection::executeQuery(string statement){
//Pool::locke();
//cout << "0.start query" << endl;
const char* query = statement.c_str();
//cout << "1.before mysql_real_query" << endl;
//cout << "strlen=[" << strlen(query) << "]" << endl;
unsigned int len = (unsigned int) strlen(query);
char q[100];
strncpy(q,query,len);
q[len]=0;
int status = mysql_real_query(conn,q,len);
//cout << "1.after mysql_real_query" << endl;
if(status){
printf("Error making query: %s\n",
mysql_error(conn));
}
else{
//printf("[%s] made...\n", query);
}
MYSQL_RES* resultSet;
//cout << "2.before mysql_store_result" << endl;
resultSet = mysql_store_result(conn);
//cout << "2.after mysql_store_result" << endl;
//cout << "3.before mysql_fetch_row" << endl;
QueryResult queryResult;
while(true){
MYSQL_ROW row;
if(!(row = mysql_fetch_row(resultSet))){
break;
}
vector<string> string_row;
for(int i=0; i < mysql_num_fields(resultSet); i++){
string_row.push_back(row[i]);
}
queryResult.addRow(string_row);
}
//cout << "3.after mysql_fetch_row" << endl;
//cout << "4.before mysql_free_result" << endl;
mysql_free_result(resultSet); //free result after you get the result
//cout << "4.after mysql_free_result" << endl;
//cout << "0.finish query" << endl;
//Pool::unlocke();
return queryResult;
}
mine.cpp ( 3 in 3 )
#include "pool.h"
#include <unistd.h>
#include <stdlib.h>
using std::cout;
using std::endl;
void* handler(void* arg){
long tid = (long)arg;
//cout << "tid =[" << tid << "]" << endl;
Connection* conn = Pool::getConnection();
if(!conn){
cout << "getConnection NULL pointer" << endl;
exit(-1);
}
//cout << "Connection.this:" << conn << endl;
const char* query;
query = "select * from student;";
QueryResult queryResult = conn->executeQuery(query);
Pool::releaseConnection(conn);
//for(int i=0;i<queryResult.getRowCount();i++){
// for(int j=0;j<queryResult.getColumnCount();j++){
// cout << queryResult.getElement(i,j) << " ";
// }
// cout << endl;
//}
}
int main(int argc, char* argv[]){
string host = "localhost";
string user = "root";
string pass = "jiqim1ma";
string dbname = "hcx";
int poolSize = 152;
Pool::initPool(host,user,pass,dbname,poolSize);
///std::cin.get();
unsigned int count = -1;
if(argc>1){
count = atoi(argv[1]);
}
for(int i=0;i < count;i++){
const int THREAD_COUNT = 250;
pthread_t threads[THREAD_COUNT];
for(long i=0;i<THREAD_COUNT;i++){
pthread_create(&threads[i],NULL,handler,(void*)i);
//sleep(1);
}
for(int i=0;i<THREAD_COUNT;i++){
pthread_join(threads[i],0);
}
cout << "==============================LOOPBACK=================================" << endl;
}
Pool::destroyPool();
return 0;
}
Makefile
all: sbpool
sbpool: mine.cpp pool.cpp
g++ -g -o sbpool mine.cpp pool.cpp -lmysqlclient -lpthread
clean:
rm -f *.o accessdb sbpool core*
来源:oschina
链接:https://my.oschina.net/u/1179554/blog/149560