6

Delphi で複数のスレッドが作成された dll ライブラリを作成しています。問題を順を追って説明します。事前の説明が長くなってしまい申し訳ありません:-(。

しばらく図書館のことは忘れましょう。複数のカメラからのビューを表示する Windows アプリケーションを作成しました。単一のカメラからのビューを表示するためのウィンドウを作成しました。ウィンドウには TImage コントロールが含まれています。数ミリ秒ごとにカメラから現在の画像をダウンロードし、そのウィンドウの TImage コントロールに割り当てるスレッド (TThread の子孫) があります (Synchronize() メソッドを使用)。アプリケーションは、起動時にそのウィンドウの複数のインスタンスを (それぞれに別のスレッドで) 作成するため、複数のカメラからのライブ ビューを一度に見ることができます。さらに、これらの表示ウィンドウはすべてメイン アプリケーション ウィンドウの親であり、メイン アプリケーション ウィンドウ内に表示されます。

これらの 2 つのウィンドウを dll ライブラリに入れることを決定するまで、すべてが正常に機能していました。いくつかの理由で必要だと思いましたが、今は重要ではありません。そこで、新しい dll ライブラリを作成し、既存のメイン ウィンドウとカメラ ビュー ウィンドウをプロジェクトに追加し、メイン ウィンドウのインスタンスを作成して返す関数をエクスポートしました。メイン ウィンドウが作成されると、いくつかのカメラ ビュー ウィンドウが作成され、それ自体が親になります。

次に、テスト目的で、上記の dll 関数をライブラリからインポートし、起動時にそれを呼び出してメイン ウィンドウのインスタンスを取得するアプリを作成しました。次に、それを画面に表示します(非モーダル状態)。

アプリを起動すると、どのカメラからも画像を 1 枚も取得できないことがわかりました。デバッグしたところ、スレッドが Synchronize() メソッドを呼び出すと、スレッドが永久にハングすることに気付きました。これらの両方のウィンドウを dll に入れる前は、この問題は発生しませんでした。

そして、これは私の問題です。正直なところ、これはライブラリに対する私の最初のアプローチであり、これまでに他の多くの問題を乗り越えなければなりませんでした。フレームの代わりにウィンドウを使用する理由を不思議に思うかもしれません...そのため、dll で TFrame のインスタンスを作成するたびに、「コントロール xxx には親ウィンドウがありません」という例外が発生します。私はそれについて何をすべきかわからなかったので、代わりにウィンドウを使用しました:-(。

同期の問題の対処法を教えてください。メインスレッドは、ボタンのクリックなどを受け入れるため、アプリケーションが開始されたときにブロックされていないようです。問題は何ですか?

助けてください!

前もって感謝します!!

4

3 に答える 3

13

スレッドを呼び出すTThread.Synchronizeと、メソッド ポインターがSyncList: TListClasses.pas のグローバルに追加されます。メインの exe のTApplication.Idleルーチン呼び出しではCheckSynchronize、 をチェックしますSyncListが、DLL 内のバージョンではなく、exe 内のバージョンをチェックします。最終結果、同期されたメソッドが呼び出されることはありません。

最も簡単な解決策は、DLL からパッケージに切り替えることです。これにより、重複がなくなりますSyncList

別のアプローチは、exe のApplication.OnIdleコールバックをオーバーライドし、DLL をCheckSynchronize手動で呼び出すことです。Applicationただし、DLL にもオブジェクトがあり、そのオブジェクトは機能しないため、そのためにはアプリケーションの助けが必要です。

于 2010-09-22T18:22:18.863 に答える
3

このような競合状態につながる傾向があるため、Synchronize を使用することはお勧めできません。あなたのコードで具体的に何が起こっているのかはわかりません。コードを見ないとわかりませんが、この種の問題は実際にはかなり一般的です。

スレッド間通信は、キューを使用する方が適切です。最新バージョンの Delphi XE をお持ちの場合は、この種の作業に最適なTThreadedQueue<T>クラスがあります。Generics.Collections次のように、コンストラクターの PopTimeout パラメータに 0 を渡し、カメラ スレッドに画像をプッシュさせ、メイン スレッドに 3 番目の PopItem オーバーロードでキューをポーリングさせます。

var
  CurrentItem: TImage;
begin
  if ThreadQueue.PopItem(CurrentItem) = wrSignaled then
    UpdateImage(CurrentItem); //or however you do it
end;

(キューに何もない場合、PopItem は代わりに wrTimeout を返します。)

Delphi XE をお持ちでない場合は、独自のスレッドセーフ キューを作成するか、Primoz Gabrielcic のOmniThreadLibrary などのサード パーティ ソースから見つける必要があります。

于 2010-09-22T18:26:35.437 に答える
0

スレッドのハングアップを解決する2つの方法を見つけましSynchronize()た(Delphi 7で):

  1. TTimerDll フォームとonTimerイベント呼び出しにa を配置しますCheckSynchronize

procedure TPluginForm.Timer1Timer(Sender: TObject); begin CheckSynchronize; end;

  1. このモジュールを Dll フォームの uses セクションに追加します
于 2016-01-22T14:40:50.830 に答える