2010-5-15
今天早上接到老总电话,平台又卡住了。远程上去,是user breakpoint from at对话框,确定后,程序的调用栈大致为
new失败
ado的GetField...
binder.ObjectFromDB(prs)
QUERY_MDB_COMMAND((CMD_QUERY_SERVER,svr_id),CServerBinder,*server,result);
server_helper_.Get(serverid,&server);
server = dap_->GetServer(org->GetSvrID());
int CRTOPlugin::HandleSend(CMsg *msg,CWrappedMsg<> **wm)
查找附近代码,发现一处线程安全问题。
CTableInfo* HTX_DB_Helper::OpenTable(CDbAccessor *pdbor,const char *tbl_name) {
// string s = tbl_name;
// StringToUpper(s);
string s = StringToUpper(tbl_name);
CTableInfo *pti = this->FindTable(s.c_str());
if (pti)
return pti;
pti = new CTableInfo();
pti->SetDbAccessor(pdbor);
if (pti->Init(tbl_name)) {
delete pti;
return 0;
}
use_tables_.bind(s.c_str(),pti);///<use_tables_容器是非线性安全的。
return pti;
}
use_tables_容器是非线性安全的,其定义如下
typedef ACE_Hash_Map_Manager<ACE_CString,CTableInfo*,ACE_Null_Mutex> MAP_DB_TABLE;
MAP_DB_TABLE use_tables_;
所以,当多线程下同时访问OpenTable时,会存在不可预期。
修改如下:
typedef ACE_Hash_Map_Manager<ACE_CString,CTableInfo*,ACE_Recursive_Thread_Mutex> MAP_DB_TABLE;
当绑定失败后,会存在内存泄漏(不过量很小),临时修改如下:
CTableInfo* HTX_DB_Helper::OpenTable(CDbAccessor *pdbor,const char *tbl_name) {
CTableInfo *pti = 0;
use_tables_.mutex().acquire();
if( -1 == use_tables_.find(tbl_name) ){
pti = new CTableInfo();
pti->SetDbAccessor(pdbor);
if (pti->Init(tbl_name)) {///<保证init没有异常抛出,否则会有死锁
use_tables_.mutex().release();
delete pti;
return 0;
}
use_tables_.bind(tbl_name,pti);
}
use_tables_.mutex().release();
return pti;
}
ITableHandler* HTX_DB_Helper::NewTableHandler(CDbAccessor *pdbor,const char *tbl_name) {
CTableInfo *tbl;
string s = StringToUpper(tbl_name);
tbl = this->FindTable(s.c_str());
if (tbl==NULL)
tbl = this->OpenTable(pdbor,s.c_str());///<当查找失败后,才OpenTable。Opentable是线程互斥的
CTableHandler *th = 0;
if (tbl) {
th = new CTableHandler;
th->Attach(tbl);
th->SetDbAccessor(pdbor);
}
return th;
}
替换程序,顺便把客户通、商机中心、计费系统的后台线程停掉,于16:40,在非debug模式下重启平台。