4

私はDLLに関して少し設計上の問題があります.あなたがそれを呼ぶかもしれないし、ウィキペディアがそれを参照しているように、私は現在、DLL Hellにいます問題は次のとおりです:

複数のモジュールを DLL として実装したシステムを作成しました。これらはアプリケーションで使用され、DLL をロードできますが、すべてが必要なわけではありません。数学のようなことだけが行われている場合は、「Utilities.dll」にリンクしてこれを使用できます。問題は、ロガー/トレーサーを持っていることです。これにより、すべてがファイルとデバッグ コンソールに記録されます。デバッグ コンソールは単なるストリーム出力です。問題は、複数の DLL が同じログ クラスを操作しようとする場合の対処方法です。ログ クラスはこの「Utilities.dll」にあり、「DataManagers.dll」や他の dll などはログ クラス機能も使用したいと考えています。これには、ファイルへのロギングが含まれます。現在、クリティカル セクションを使用して書き込みの衝突が発生しないようにしていますが、クリティカル セクションがユーザーモードで実装されているのを確認しています。カーネル モード オブジェクトを使用するには、ある時点でミューテックスなどに切り替える必要があります。しかし、DLL メモリ全体にログ クラスのインスタンスが複数あるということは、クリティカル セクションを使用するだけでは深刻な問題が発生することを意味します。

私が理解できないのは、Utilities.dll に 1 つずつリンクしなくても、すべての DLL が同じログ クラス インスタンスを使用できるようにする方法です。私はデモ プロジェクトに 8 つの dll をロードしたくありません。これら 8 つすべてがログ クラスでその 1 つの dll を参照するようにします。ログ クラスのようなものがさらに必要な場合、これはちょっとした連鎖反応になります。これを適切に行う方法はありますか?他の DLL 内の DLL 内の静的関数と、同じ「静的」関数を使用する .exe Windows バイナリでクラスの機能を使用することにより、ログファイルへの書き込みやデバッグ コンソールの出力ストリームでさえ衝突しません。

そして、私が完全に間違っていて、不可能なことをしようとしている場合は、私に教えて、できるだけこれに近いものを達成するのを手伝ってください. DLLでSingletonパターンを使用すると、同様の問題が発生することはわかっていますが、これは次の方法で解決されます

私がこれまでに試したこと:

  • DLL のクラスを初期化するときに、ログ ライブラリのインスタンスを与えますが、これはすべての静的メンバーを持つクラスの目的を無効にします。

同様のこの質問も見つけました(ライブラリの名前でさえ、私のグローバルツールはそれについてどうですか..)が、それは私の質問に答えておらず、'09からのものであるだけでなく、少し異なるアプローチを持っています. 静的ライブラリの「アプリケーション内のグローバル変数の複数のインスタンス」の動作を模倣するが、DLL を使用する方法は?

4

3 に答える 3

5

あなたの問題は「DLL Hell」ではありません。

DLL がどのように機能するかについての基本的な理解の問題です。DLL は、プロセスごとに最大 1 回読み込まれます。そのため、DLL が他の複数の DLL によって使用されている場合でも、プロセスごとに 1 回存在します。ログ クラス オブジェクトが DLL でシングルトンとして実装されている場合 (グローバル オブジェクトなど)、プロセスごとに 1 つのオブジェクトがあります。

その 1 つのオブジェクトは、プロセス内での同時使用から保護する必要があります。クリティカル セクションはプロセス ローカルであるため、これに最適です。2 つのプロセスがそれぞれ Utilities.DLL とそのオブジェクトの独自のコピーを持つため、ミューテックスは必要ありません。

ロガーが単一の固定ファイルにログを記録する場合、問題が発生する可能性があります。その場合、2 つのプロセスが同じファイルにログを記録しようとします。とにかくハッキングしたくない設計上の問題です。ログ出力を個別に保持するため、各ロガーが一意のログ ファイルに書き込むようにしてください。

于 2012-05-22T07:19:19.767 に答える
1

下の画像からわかるように画像

プロセス内で 1 つの DLL を複数回マップすることは、実際には非常に一般的です (非常に一般的な意見とは異なります)。DLLがどのように機能するかを基本的に理解することが問題です:-)

クリーンな Windows XP システムでは、iexplore.exe プロセス内に dxtmsft.dll、ieframe.dll、iepeers.dll などのインスタンスがいくつかあります。これらの Dll はすべて、異なるアドレスにマップされているだけです。

于 2012-06-22T11:28:44.400 に答える
0

Windows の共有メモリを使用するキューのような通信セクションである WinApi の CreatePipe または CreateNamedPipe 関数を使用します。

    BOOL WINAPI CreatePipe(
  __out         PHANDLE hReadPipe,
  __out         PHANDLE hWritePipe,
  __in          LPSECURITY_ATTRIBUTES lpPipeAttributes,
  __in          DWORD nSize
);

また

    HANDLE WINAPI CreateNamedPipe(
  __in          LPCTSTR lpName,
  __in          DWORD dwOpenMode,
  __in          DWORD dwPipeMode,
  __in          DWORD nMaxInstances,
  __in          DWORD nOutBufferSize,
  __in          DWORD nInBufferSize,
  __in          DWORD nDefaultTimeOut,
  __in          LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

ReadFile と WriteFile を使用して、他のスレッド/プロセス内からパイプを介して通信します。

パイプから読み取るために、プロセスは ReadFile 関数の呼び出しで読み取りハンドルを使用します。ReadFile は、パイプの書き込み側で書き込み操作が完了した場合、要求されたバイト数が読み取られた場合、またはエラーが発生した場合のいずれかが true の場合に返されます。

プロセスが WriteFile を使用して匿名パイプに書き込む場合、すべてのバイトが書き込まれるまで書き込み操作は完了しません。すべてのバイトが書き込まれる前にパイプ バッファーがいっぱいになると、別のプロセスまたはスレッドが ReadFile を使用してより多くのバッファー領域を使用できるようになるまで、WriteFile は戻りません。

1 つのスレッドを使用して入力を処理し、ログをファイルやコンソールに書き込みます。

パイプの詳細: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365780(v=vs.85).aspx

于 2012-05-21T23:45:42.340 に答える