最近待業,閒的蛋疼,發現C++下連mysql鏈接池這麼基礎的東西都沒用過,身爲一名計算機畢業生,深感愧疚,遂生一想法,寫個或者找個鏈接池,以加強本人垃圾同樣的專業修養。 mysql
沒想到寫出來初版就存在內存管理問題致使的coredump,查了半天,發現是調用了空指針的成員函數,完全暈倒,其間爲了調試gdb core中bt出來的libmysqlclient.so的mysql_real_connect調用,我下了mysql的5.5.31源代碼來編了若干遍,想編個debug版調試最後也是沒有成功。發現問題仍是看網上帖子講segfault11這種問題多半都是空指針搞的,反過頭加了些指針的打印語句才意識到低級的錯誤,後來debug過程當中還發現了更低級的邏輯錯誤,略去不表,仍是本身太菜,連個空指針這個白癡的內存問題都不預先防範,搞得一個300+行的東西,弄了三天才算穩定了,大大的罪過,浪費本身和社會的生產力。 ios
過程當中想到本身既然寫很差,乾脆找個好用的,結果發現了個libzdb,支持好些個開源db的鏈接池,隨便下了個破代碼測了一下,也沒仔細搞,debug中參考了一下它的源碼,還算是有點啓發。 git
目前這個源碼用valgrind本身測,有74KB左右的內存泄露,明白人能改改的話最好,做爲一個菜鳥我只能幫本身到這了,固然這個泄露不會隨時間線性的增加,這個我仍是測過了的,有人能用到生產環境的話,麻煩給我提點改進意見,72小時的做品,太經不起考驗了,目前本機上只能支持最多 152條鏈接,設成153就會報鏈接失敗,牛逼的前輩們狠狠的批這份代碼好了,本身也感受本身水平太殘廢了,不知道是mysql設置仍是系統設置的問題,總之不管是建議仍是問題儘管扔過來吧,做爲一個傻逼二貨我照單全收。 github
上代碼 sql
去Github搞代碼看這裏 https://github.com/githcx/xPool shell
pool.h (1 in 3) tcp
#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 ) fetch
#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 this
all: sbpool sbpool: mine.cpp pool.cpp g++ -g -o sbpool mine.cpp pool.cpp -lmysqlclient -lpthread clean: rm -f *.o accessdb sbpool core*