状況:
Delphi 7 で記述されたアプリケーションとプラグイン dll があります。
dll は、createobject:pointer、runobject(instance:pointer)、freeobject(instance:pointer) の 3 つの関数をエクスポートします。
createobject:pointer は、dll 内部作業オブジェクトのインスタンスを作成し、オブジェクトへのポインターを返します。
runobject(instance:pointer) は、このインスタンス ポインターをパラメーターとして受け取り、このポインターを使用して、このインスタンス ポインターが指すオブジェクト インスタンス内の処理関数を開始します。
freeobject(instance:pointer) は、インスタンス ポインターを受け取り、このインスタンス ポインターが指す内部オブジェクトを解放します。
これを行ったのは、プラグイン dll から複数の作業オブジェクト インスタンスを作成できるようにするためです。
ここで、アプリケーションは 2 つのワーカースレッドをセットアップします。2 つのスレッドを設定している間、プラグイン dll は loadlibrary を介して 2 回 (スレッドごとに 1 回) 動的にロードされ、エクスポートされた関数がスレッドに渡されます。(注: 同じファイル名の同じ DLL であるため、DLL はアプリケーションに 1 回だけ読み込まれ、読み込まれた dll の参照カウントは 2 になります。)
各ワーカースレッドが起動し、CoInitialize(nil) を呼び出して com システムを初期化し (ado コンポーネントを使用したいため)、dllfunction createobject を介して独自の dll 内部オブジェクトを作成し、返された instancepointer をパラメーターとして runobject を呼び出します。
現在、runobject 内のコードは、adoconnection + adoquery コンポーネントを使用してデータベースから読み取ります。
The adocomponents are created inside the workobject and nothing is shared between the 2 threads... no global vars used.
The problem:
I get strange random accessviolations while the 2 objectinstances, each on its own thread, use their own ado components to read from the DB...!?
Both threads start to read some Databaserows. Then, at some random time and "random place" in the adoquery read code, exceptions are being raised.
"Random place" means, that the exceptions sometimes occur in the call to adoquery.open, sometimes in the call to adoquery.next... the ado code is really simple... it looks like this:
with adoquery do
begin
sql.clear;
sql.add('select * from sometable');
open;
while not eof do
begin
test := fieldbyname('test').asstring;
next;
end;
close
end;
I did some testing:
a) If I use only 1 thread (and so only 1 workobject inside the dll is beeing created) then everything works fine.
b) 別のファイル名で DLL ファイルのコピーを作成しますが、このファイル内のコードは同じで、thread_1 が dll_1 をロードし、thread_2 が dll_2 をロードすると、これら 2 つの同一の dll が両方ともアプリケーションにロードされ、すべて正常に動作します。 : このテストの loadlibrary は、各ワーカースレッドのコンテキストではなく、メインスレッドのコンテキストから呼び出されましたが、例外が発生しなかったため、問題はないように見えました。)
c) DLL をまったく使用せず、2 つのスレッドで 2 つの作業オブジェクトを直接作成すると、すべて正常に動作します。
例外は、2 つのスレッドで作成された 2 つの個別の作業オブジェクトで adocomponents を使用し、作業オブジェクトの作成コードがアプリケーションに 1 回だけ読み込まれる dll 内にある場合にのみ発生します。
質問:
エクスポートされた関数を dll から呼び出す場合、dll をロードした loadlibrary 呼び出しをスレッドのコンテキスト内から呼び出す必要がありますか? これは事実ではないと思います (テスト b) を参照してください) が、おそらく誰かがよりよく知っている!? 「これが私の問題を引き起こしている可能性がありますか? この場合、複数のスレッドから 1 つの dll の関数を使用する方法はないようです!?
これらの奇妙な例外の原因を知っている人はいますか?
ヘルプ/アイデア/説明/提案は大歓迎です。