创建连接的生产者线程
mutex _queueMutex; //维护连接队列的线程安全互斥锁
通过返回智能指针来控制连接的释放,当连接出作用域的时候,智能指针自动调用析构函数,此时只要修改析构函数,让他把资源归还给连接池,而不是删除就可以。
.头文件中添加 void produceConnectionTask();//运行在独立的线程中,专门负责生产新连接
源文件中实现
void ConnectionPool::produceConnectionTask()
{
for (;;)
{
unique_lock<mutex> lock(_queueMutex);
while (!_connectionQue.empty())
{
cv.wait(lock);//队列不空,此处生产线程进入等待状态
}
//连接数量没有到达上限,继续创建新连接
if (_connectionCnt < _maxSize)
{
connection* p = new connection();
p->connect(_ip, _port, _username, _password, _dbname);
_connectionQue.push(p);
_connectionCnt++;
}
//通知消费者线程可以消费连接了
cv.notify_all();
}
}
其中 condition_variable cv;//设置条件变量,用于连接生产线程和连接消费线程的通信
生产者逻辑:
连接池非空,生产者就等待。
如果连接池空了,生产者就检查,此时连接数量是否超过了设置的最大连接数
如果没有到达上限,就创建新连接
通知消费者线程可以消费连接
消费连接的消费者线程代码实践
给外部提供接口,从连接池中获取一个可用的空闲连接
头文件添加:shared_ptr< connection> getConnection();
源文件实现:
shared_ptr<connection> ConnectionPool::getConnection()
{
unique_lock<mutex> lock(_queueMutex);
while(_connectionQue.empty())//如果队列空了,即没有连接给我使用
{
//等待最大空闲时间
if (cv_status::timeout == cv.wait_for
(lock, chrono::milliseconds(_connectionTimeout)))
{
if (_connectionQue.empty())
{
LOG("获取空闲连接超时了...获取连接失败!");
return nullptr;
}
}
}
/*
shared_ptr智能指针析构时,会把connection资源delete掉,相当于
调用connection的析构函数,connection就被close掉了,这里
需要自定义shared_ptr的释放资源方式,把connection直接归还到queue当中
*/
shared_ptr<connection> sp(_connectionQue.front(),
[&](connection* pcon) {
//是在服务器应用线程中调用的,所以一定要考虑队列的线程安全操作
unique_lock<mutex> lock(_queueMutex);
_connectionQue.push(pcon);
});
_connectionQue.pop();
//消费了队列中最后一个connection,就要通知一下生产者连接
cv.notify_all();
return sp;
}
不能使用sleep来控制等待最大空闲时间
因为sleep就直接睡那么长时间了,即使有了新连接可以用,也会睡觉。
消费者逻辑:
当队列空时
---- 等待最大空闲时间
---- ---- 如果超时,获取连接失败,返回nullptr
---- ---- 如果在最大空闲时间内获取,检查到非空,则跳出循环
队列不为空
检查没有超过最大连接数量
创建连接,定义使用后资源的放回
通知生产者,我已经消费了一个连接,让生产者看看是否该生产了
最大空闲时间回收,扫描线程代码实践
在connection.h中添加有关时间的操作(应有三处)
//刷新一下连接的起始空闲时间点
void refreshAliveTime() {
_alivetime = clock(); }
//返回存活的时间
clock_t getAliveTime() {
return clock() - _alivetime; }
private:
MYSQL* _conn;
clock_t _alivetime;//记录进入空闲状态后的起始存活时间
在mys