程序功能:
实现了一个TCP Server端,接收到客户端连接后,新增一个单独的线程与客户端交互,中间有数据库操作,完成后线程关闭。
实现方式是VC++,数据库访问采用的是ADO,数据库是Mariadb,odbc数据源, mysql-connector。
最初的方式是每次数据库操作都是 新建ADO._Connection,打开链接,查询或提交,关闭链接 ;
问题:
结果发现运行一段时间后进程句柄数一直在增加,然后就挂了。
解决:
修改为使用ADO的连接池,重用程序启动时创建的连接池中的连接,从结果看是句柄数正常了,没有出现句柄数一直增加的情况。
实现方式如下:
(ADO是基于COM的,涉及到跨线程调用的问题,故采用全局接口表的方式)
首先在程序主线程
获取全局接口表指针
::CoInitialize(NULL);
HRESULT hr = S_OK;
CComPtr<IGlobalInterfaceTable>gpGIT;
hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGlobalInterfaceTable,
(void **)&gpGIT);
创建个ADO._Connection对象的数组m_spAdoConn,实例化对象。并注册到全局接口表,保存对应的cookieid。
for(int i=0;i<N;i++)
{
hr = m_spAdoConn[i].CoCreateInstance(__uuidof(Connection));
ATLASSERT(SUCCEEDED(hr));
hr = m_spAdoConn[i]->Open(_bstr_t(szDsn),_bstr_t(""),_bstr_t(""),0);
//注册到GIT
DWORD dwCookie = 0;
gpGIT->RegisterInterfaceInGlobal(m_spAdoConn[i],__uuidof(_Connection),&dwCookie);
gitInfo[i].cookieId = dwCookie;
}
控制_Connection的使用,我选择的是使用Semaphore
hSem = CreateSemaphore(N)
在访问数据库之前首先waitforsingleobject(hSem),从gitInfo中获取空闲的句柄,获取后置为使用中。
在使用完成后将对应的句柄标识为空闲。释放hSem。
因gitInfo需要多线程使用,使用了一个单独的CriticalSection控制。
for(int i=0;i<=N;i++){
if(gitInfo[i].blLocked==FALSE)
{
gitInfo[i].blLocked=TRUE;
cookieId = gitInfo[i].cookieId;
break;
}
}
CComPtr<IGlobalInterfaceTable>gpGIT;
hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGlobalInterfaceTable,
(void **)&gpGIT);
ATLASSERT(SUCCEEDED(hr));
gpGIT->GetInterfaceFromGlobal(cookieId,__uuidof(_Connection),(void**)&spConn);