0

Windows Embedded Compact 7 (別名 Windows Embedded CE 7) サービスを開発しています。Boost.Logライブラリはログ記録に使用され、場合によってはBoost Thread ライブラリが使用されます。xxx_IOControlサービス メソッドからログ エントリを追加しようとすると、クラッシュします。

調査の結果、クラッシュの理由は、thread.cpp ブースト スレッド ソース ファイルの add_thread_exit_function で NULL ポインターを逆参照していることがわかりました。NULL ポインター自体の最初の理由は、TlsGetValue/TlsSetValue Windows API 関数の不適切な動作である可能性があります。具体的には、次のコードで:

BOOL setOk = TlsSetValue(tlsKey, originalData);
LPVOID returnedData = TlsGetValue(tlsKey);

xxx_IOControl 呼び出し内で呼び出された場合、returnedData は NULL ですが、originalData は NULL ではありません。setOk が TRUE で、両方の TlsXXX 関数が ERROR_SUCCESS を返した後に GetLastError() が呼び出されています。同じコードがxxx_Init呼び出し内で呼び出されている間、returnedData は originalData 値と正しく等しく返されます。両方の呼び出し (xxx_Init と xxx_IOControl) で同じ tlsKey が使用され、それらの間にTlsFree呼び出しはありません。

また、おそらく関連している事実がもう 1 つあります。サービスDLLとboost_thread.dllの両方で、xxx_IOControlを呼び出すスレッドに対してDllMain(DLL_THREAD_ATTACH)が呼び出されません。

Windows CE サービス用の特別なスレッド機構はありますか? 誰かに役立つ関連情報はありますか?

4

2 に答える 2

1

そうです、Windows CE サービスはドライバーとして管理され、CE 6 以降ではユーザー モード ドライバーです。呼び出し元のスレッドは、別のプロセス (カーネル モード ドライバーの場合は nk、サービスの場合はサービス) のコンテキストで "移行" し、呼び出し時にそのアドレス空間にアクセスできます (通常、通常のプロセス内で実行している場合は不可能なことです)。処理する)。移行はスレッドの作成とは異なります。スレッドが独自のプロセス アドレス空間に移行するときに DllMain が呼び出されないのはそのためです。GetDirectCallerProcessId() は、呼び出し元のプロセス ID を返します (XXX_IoControl 内だけでなく、任意の XXX_* 関数で) が、発生した TLS の問題にはあまり役立ちません。別のアプローチは、辞書を使用して、現在 TLS を使用してスレッドに関連付けられている情報を格納することです。スレッドが別のプロセスで閉じられたときに通知を受け取らないため、特定のスレッドのデータをいつ解放できるかわかりませんが、 processid+threadid をキーとして使用し、内部辞書からすべてのキーを削除することでこれを克服できますXXX_Close エントリ ポイントが呼び出されたときの特定のプロセスに関連します (プロセスがハンドルを閉じると、ioctl を呼び出すことができなくなり、プロセスが終了すると、そのハンドルが閉じられることが許可されるため、XXX_close 関数が 1 回呼び出されます)。 . 間にハンドルを閉じずに異なるスレッドからサービスを呼び出すプロセスがある場合、それが問題となり、システムでメモリ リークが発生する可能性があります。

于 2014-08-13T12:01:00.437 に答える