使用互斥锁使连接池线程的类安全(C ++)

我试图编写一个在初始化时创建X MySQL连接池的类。

然后,我的主程序应该能够启动多个线程,其中每个线程都通过从池中获取一个连接来调用一个函数以写入数据库-一旦有一个连接可用,然后将其返回到池中写操作完成后。

现在,我想通过对类的关键部分使用互斥锁lock_guard锁来使“ ConnectionPool”类具有线程安全性-我将其标识为以下方法:

  • getconn():方法,该方法将一个连接从池(连接向量)返回到请求线程以进行写操作
  • returnConn():该方法在写入数据库后将一个连接返回给池

不幸的是,该程序有时会因以下错误而崩溃:

使用互斥锁使连接池线程的类安全(C ++)

有时,当前使用的可用连接数也有误(可能导致程序崩溃):

例如(具有5个连接的池):

使用互斥锁使连接池线程的类安全(C ++)

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_;
}
bufenglangzi 回答:使用互斥锁使连接池线程的类安全(C ++)

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/2328657.html

大家都在问