0

C++ Builder XE3 を使用しています。Windows サービスでは、関数 tcp_serverExecute(TIdContext *AContext) で ( Indy TCP サーバー ) に IdTCP サーバーがあります。これは、私が理解しているように、新しいスレッドを生成します。

TADOConnection と TADOQuery を作成します ( CoInitialize を呼び出した後) 問題は、サービス オブジェクトを接続とクエリの親として使用しない限り、アプリケーションで常にメモリ リークが発生することです。

  ::CoInitialize(NULL);
  TADOConnection * sql_conn = new TADOConnection(service_object);
  TADOQuery * pos_q = new TADOQuery(service_object);

try
{

}
__finally
{
  delete pos_q;
  delete sql_conn;
  ::CoUninitialize();
}

ただし、サービス オブジェクトを親として使用すると、最終的に例外が発生し、アプリケーションがクラッシュします。親( owner )に NULL を使用すると、問題なく動作しますが、プロセスはメモリ内で成長し続けます。TThreadで同様のコードを実行した場合、私が認識してテストした限り、同じ問題は発生しません。

4

2 に答える 2

0

OwnerとしてNULLを渡し、作成されたオブジェクトを自分で削除する必要があります。また、スレッド内で CoInitialize と CoUninitialize を呼び出すのは危険です。フォーム コンストラクターとデストラクタに入れます。

TADOConnection * sql_conn = new TADOConnection(NULL);
TADOQuery * pos_q = new TADOQuery(NULL);

try
{
}
__finally
{
    delete pos_q;
    delete sql_conn;
}
于 2013-10-20T17:04:15.723 に答える
0

COM はスレッドごとに 1 回だけ初期化する必要がありますが、OnExecuteイベントはクライアントの存続期間中に複数回トリガーされます。

(コンポーネントをプロパティにTIdTCPServerアタッチすることにより)でスレッド プールを使用していない場合は、およびイベントを使用して ADO オブジェクトを初期化/終了し、必要に応じてイベントで使用できます。次に例を示します。TIdSchedulerOfThreadPoolTIdTCPServer::SchedulerTIdTCPServer::OnConnectTIdTCPServer::OnDisconnectTIdTCPServer::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...
}
于 2013-11-20T03:02:24.070 に答える