我试图编写一个在初始化时创建X MySQL连接池的类。
然后,我的主程序应该能够启动多个线程,其中每个线程都通过从池中获取一个连接来调用一个函数以写入数据库-一旦有一个连接可用,然后将其返回到池中写操作完成后。
现在,我想通过对类的关键部分使用互斥锁lock_guard锁来使“ ConnectionPool”类具有线程安全性-我将其标识为以下方法:
- getconn():方法,该方法将一个连接从池(连接向量)返回到请求线程以进行写操作
- returnConn():该方法在写入数据库后将一个连接返回给池
有时,当前使用的可用连接数也有误(可能导致程序崩溃):
例如(具有5个连接的池):
Main()和writeDB():
int main() {
string DB_SERVERNAME = "localhost";
string DB_username = "root";
string DB_PASSWORD = "password";
string DB_NAME = "testdb";
unsigned int DB_PORT = 3307;
vector<thread> threadVec;
mysql_library_init(0,NULL,NULL);
ConnectionPool cpool(DB_SERVERNAME,DB_username,DB_PASSWORD,DB_NAME,DB_PORT);
cout << cpool.getServername() << endl;
ConnectionPool* ptrCpool = &cpool; //Pointer to object cpool of Class "ConnectionPool"
cpool.initPool(5);
unsigned long long timestamp = 1111111;
float value = 1;
for (int i = 0; i < 20; i++) {
//thread t(writeDB,i,ptrCpool,timestamp,value);
threadVec.emplace_back(writeDB,value);
threadVec.at(i).detach();
timestamp += 1111111;
value++;
}
mysql_library_end();
return 1;
}
void writeDB(int threadNo,ConnectionPool* ptrCpool,unsigned long long timestamp,float value) {
cout << "____________________________________________" << endl;
cout << "Thread " << threadNo << " started." << endl;
MYSQL* conn = ptrCpool->getconn();
if (!conn) {
cout << "failed to get connection " << threadNo << endl;
return;
}
cout << "Established connection " << conn << " on Thread #" << threadNo << endl;
cout << "ConnAvailable: " << ptrCpool->getconnAvailable() << endl;
cout << "ConnInUse: " << ptrCpool->getconnInUse() << endl;
cout << "____________________________________________" << endl;
//Writing to DB here
//...
Sleep(5000); //Using conn for x seconds before returning it to pool
ptrCpool->returnConn(conn);
mysql_thread_end();
}
ConnectionPool.h
class ConnectionPool
{
private:
//Connection Settings
std::string DB_SERVERNAME_;
std::string DB_username_;
std::string DB_PASSWORD_;
std::string DB_NAME_;
unsigned int DB_PORT_;
//ConnectionPool Variables
MYSQL* conn_;
int poolSize_;
int connAvailable_ = poolSize_;
int connInUse_ = 0;
std::vector<MYSQL*> pool_;
bool poolState_ = false; //True if initialized
std::mutex mtx;
public:
//Constructor
ConnectionPool(std::string,std::string,unsigned int);
//Initialize Pool
void initPool(int);
//setter
//...
void returnConn(MYSQL*);
//getter
//...
MYSQL* getconn();
};
ConnectionPool.cpp
#include "ConnectionPool.h"
using namespace std;
//Constructor
ConnectionPool::ConnectionPool(string DB_SERVERNAME,string DB_username,string DB_PASSWORD,string DB_NAME,unsigned int DB_PORT) {
cout << "Constructor called - setting DB Parameters" << endl;
this->DB_SERVERNAME_ = DB_SERVERNAME;
this->DB_username_ = DB_username;
this->DB_PASSWORD_ = DB_PASSWORD;
this->DB_NAME_ = DB_NAME;
this->DB_PORT_ = DB_PORT;
}
//Initialize Pool
void ConnectionPool::initPool(int poolSize) {
this->poolSize_ = poolSize;
for (int i = 0; i < poolSize; i++) {
cout << "Establishing connection " << i + 1 << endl;
conn_ = mysql_init(0); //Calls mysql_thread_init() as well
conn_ = mysql_real_connect(conn_,DB_SERVERNAME_.c_str(),DB_username_.c_str(),DB_PASSWORD_.c_str(),DB_NAME_.c_str(),DB_PORT_,0); //Arguments as const char*
if (conn_) {
cout << "Database connection " << i + 1 << " successful" << endl;
cout << "ThreadID " << conn_->thread_id << endl;
}
else {
cout << "Error: Database not connected - errno: " << mysql_errno(conn_) << endl;
return;
}
pool_.push_back(conn_); //Add connection to pool
}
connAvailable_ = poolSize_;
poolState_ = true;
cout << "Pool initialized with " << poolSize_ << " Connections" << endl;
cout << connAvailable_ << " Connections available" << endl;
}
//Setter
//...
void ConnectionPool::returnConn(MYSQL* conn) {
if (!poolState_) {
cout << "Pool not initialized yet" << endl;
return;
}
const lock_guard<mutex> lock(mtx); //lock critical part
pool_.push_back(conn);
connAvailable_ = pool_.size();
connInUse_ = poolSize_ - pool_.size();
}
//Getter
//...
MYSQL* ConnectionPool::getconn() {
if (!poolState_) {
cout << "Pool not initialized yet" << endl;
return 0;
}
while (pool_.empty()) {
Sleep(1000); //Retry after 1 second
}
const lock_guard<mutex> lock(mtx); //lock critical part
MYSQL* conn_ = pool_.back(); //Returns reference to last element of vector
pool_.pop_back(); //Deletes last element
connAvailable_ = pool_.size(); //Number of connection left in pool
connInUse_ = poolSize_ - pool_.size();
return conn_;
}