COM只应初始化每个线程一次,但在客户的整个生命周期中,多次触发事件OnExecute
。
如果你不使用线程与TIdTCPServer
池(通过附加一个TIdSchedulerOfThreadPool
组件到TIdTCPServer::Scheduler
属性),那么你可以使用TIdTCPServer::OnConnect
和TIdTCPServer::OnDisconnect
事件来初始化/完成您的ADO对象,然后在TIdTCPServer::OnExecute
事件作为使用它们需要,如:
class TMyContextData
{
public:
TADOConnection *sql_conn;
TADOQuery *pos_q;
TMyContextData();
~TMyContextData();
};
TMyContextData::TMyContextData()
{
sql_conn = new TADOConnection(NULL);
pos_q = new TADOQuery(NULL);
}
TMyContextData::~TMyContextData()
{
delete pos_q;
delete sql_conn;
}
void __fastcall TMyForm::tcp_serverConnect(TIdContext *AContext)
{
::CoInitialize(NULL);
AContext->Data = new TMyContextData;
}
void __fastcall TMyForm::tcp_serverDisconnect(TIdContext *AContext)
{
delete static_cast<TMyContextData*>(AContext->Data);
AContext->Data = NULL;
::CoUninitialize();
}
void __fastcall TMyForm::tcp_serverExecute(TIdContext *AContext)
{
TMyContextData *pData = static_cast<TMyContextData*>(AContext->Data);
// use pData->sql_conn and pData->pos_q as needed...
}
或者,从TIdServerContext
派生一个新类来代替:
class TMyContext : public TIdServerContext
{
public:
TADOConnection *sql_conn;
TADOQuery *pos_q;
__fastcall TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList = NULL);
__fastcall ~TMyContext();
};
__fastcall TMyContext::TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList)
: TIdServerContext(AConnection, AYarn, AList)
{
::CoInitialize(NULL);
sql_conn = new TADOConnection(NULL);
pos_q = new TADOQuery(NULL);
}
__fastcall TMyContext::~TMyContext()
{
delete pos_q;
delete sql_conn;
::CoUninitialize();
}
__fastcall TMyForm::TMyForm(TComponent *Owner)
: TForm(Owner)
{
// do this before activating TIdTCPServer
tcp_server->ContextClass = __classid(TMyContext);
}
void __fastcall TMyForm::tcp_serverExecute(TIdContext *AContext)
{
TMyContext *pContext = static_cast<TMyContext*>(AContext);
// use pContext->sql_conn and pContext->pos_q as needed...
}
但是,如果哟您正在使用线程池,那么多个客户端可以由相同的物理线程提供服务,因此您应该将您的COM初始化移动到管理TIdContext
对象的实际线程对象(您还应该将ADO对象移动到线程中,以便可以重用它们对于多个客户),例如:
class TMyADOThread : public TIdThreadWithTask
{
protected:
virtual void __fastcall AfterExecute();
virtual void __fastcall BeforeExecute();
public:
TADOConnection *sql_conn;
TADOQuery *pos_q;
__fastcall TMyADOThread(TIdTask *ATask = NULL, const String AName = "");
};
__fastcall TMyADOThread::TMyADOThread(TIdTask *ATask, const String AName)
: TIdThreadWithTask(ATask, AName)
{
}
void __fastcall TMyADOThread::BeforeExecute()
{
TIdThreadWithTask::BeforeExecute();
::CoInitialize(NULL);
sql_conn = new TADOConnection(NULL);
pos_q = new TADOQuery(NULL);
}
void __fastcall TMyADOThread::AfterExecute()
{
delete pos_q;
delete sql_conn;
::CoUninitialize();
TIdThreadWithTask::AfterExecute();
}
__fastcall TMyForm::TMyForm(TComponent *Owner)
: TForm(Owner)
{
// do this before activating TIdTCPServer
IdSchedulerOfThreadPool1->ThreadClass = __classid(TMyADOThread);
}
void __fastcall TMyForm::tcp_serverExecute(TIdContext *AContext)
{
TMyADOThread *pThread = static_cast<TMyADOThread*>(static_cast<TIdYarnOfThread*>(AContext->Yarn)->Thread);
// use pThread->sql_conn and pThread->pos_q as needed...
}
为什么你认为有泄漏?进程内存的增加不能保证是真实泄漏的指示。请记住,RTL缓存并重新使用释放的内存,但不会返回到操作系统。你可能会看到内存碎片,而不是内存泄漏。如果您尚未安装,则应安装[FastMM](http://fastmm.sourrceforge.net)或其他设计用于防止碎片的内存管理器。 –