2

OnTimerイベントハンドラー(TTimer)で例外が発生し、実行すると親フォームの整数変数がインクリメントされます。タイマーは、IDとして使用される増分整数にアクセスできる必要があります。

私の最初の質問は、Delphi 2007で、どのコードがどのスレッドで実行されているかをどのように判断できるかということです。デバッグモードでこれを検査して確実に判断できるようにする方法はありますか?

次に、別のスレッドから親フォームの変数にアクセスして変更する必要がある場合、それを行うための最良の方法は何ですか?Delphiでは、例外を発生させずにこれらの変数に「誤って」アクセスできる場合もあれば、例外を発生させる場合もあるようです。

4

4 に答える 4

5

念のために言っておきますが、一方ではタイマーイベントについて話しているのに対し、他方ではマルチスレッドについて話しているのです。これらは、コードを並行して実行する 2 つのまったく異なる方法です。

タイマーは常にメイン スレッドで実行されます。メインスレッドで作成され、使用されているすべてのものに安全にアクセスできるはずです。実際、タイマー イベントは、アプリケーションのメッセージ ハンドラーがタイマー メッセージを処理する必要があるため、他のメイン スレッド コードが実行されていない場合にのみ発生します。したがって、イベント処理コードの外側か、イベント ハンドラーの 1 つが Application.ProcessMessages を呼び出すときのいずれかです。

スレッドはこれとは大きく異なります。この場合、異なるスレッドのコードは互いに独立して実行されます。マルチプロセッサ マシン (またはマルチ コア) で実行している場合は、実際に並列で実行することさえ可能です。この方法で発生する可能性のある問題はかなりあります。特に、Delphi VCL (Delphi XE を含む) はスレッド セーブではないため、VCL クラスへの呼び出しはメイン スレッドからのみ行う必要があります (いくつかの例外があります)。このルール)。

したがって、有用な回答を期待する前に、まず、タイマーについて話しているのか、それとも真のマルチスレッドについて話しているのかを明確にしてください。

于 2009-02-01T09:52:55.407 に答える
3

2 つの質問をされているので、2 つの回答でお答えします。

最初の質問は、TTimers の使用に関するものです。それらは常にメインスレッドで実行されます。

ほとんどの場合、例外はアクセス違反です。

そうである場合、通常は次のいずれかが原因です。

  • a- TTimer が起動したときに親フォームが既に破棄されている。
  • b- TTimer が起動したときに、親フォームへの参照がまだありません。

b は簡単です。参照がnilかどうかを確認するだけです。

a はより難しく、親フォームをどのように参照するかによって異なります。

基本的に、親が破棄または削除されているときに参照が nil になるようにする必要があります。

グローバル変数 (この例ではForm2 )を介して親フォームを参照する場合、次のように OnDestroy イベントを使用して、TForm2 でForm2 変数をnilにする必要があります。

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm2 = class(TForm)
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormDestroy(Sender: TObject);
begin
  Form2 := nil;
end;

end.

親フォームへのフィールド参照 ( FMyForm2Reference など) を使用している場合は、次のように Notification メソッドを追加する必要があります。

unit Unit1;

interface

 uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Unit2;

 type
  TForm1 = class(TForm)
  private
    FMyForm2Reference: TForm2;
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
  end;

 var
  Form1: TForm1;

 implementation

{$R *.dfm}

 procedure TForm1.Notification(AComponent: TComponent; Operation: TOperation);
 begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) then
    if (AComponent = FMyForm2Reference) then
      FMyForm2Reference := nil;
 end;

 end.

よろしく、

ジェローン・プルイマーズ

于 2009-02-01T10:22:00.420 に答える
3

Delphi 2007 で、どのコードがどのスレッドで実行されているかを知るにはどうすればよいですか? 確実に判断できるように、デバッグモードでこれを検査する方法はありますか?

ブレークポイントを設定すると、実行が停止したときにスレッドのデバッグ ウィンドウを確認できます。各スレッドをダブルクリックして、コールスタック デバッグ ウィンドウにそのコールスタックを表示します。また、Win32 関数 GetCurrentThreadId を使用して、現在のスレッドについて調べることもできます (たとえば、ログを記録したり、現在のスレッドがメイン スレッドであるかどうかを判断したりする場合など)。

コードを表示していないため、より具体的にすることは困難です。念のため: タイマー イベント ハンドラーのコードは別のスレッドで実行されません。実際のバックグラウンド スレッドではなく、タイマーを使用しているだけであれば、同時アクセスの問題は発生しません。

次に、別のスレッドから親フォームの変数にアクセスして変更する必要がある場合、それを行う最善の方法は何ですか? Delphi では、例外を与えずにこれらの変数に「間違って」アクセスできる場合もあれば、例外を与える場合もあるようです。

実際に別のスレッドにいて、共有変数にアクセスする場合、そのアクセスを保護しないと、あらゆる種類のことが起こっていることがわかります。ほとんどの場合は問題なく動作するか、奇妙な値が得られます。スレッドセーフな方法で整数を変更したいだけなら、InterlockedIncrement を見てください。それ以外の場合は、クリティカル セクション、ミューテックス、モニターを使用できます... JEDI には、そのための JclSynch ユニットにいくつかの便利なクラスがあります。

于 2009-02-01T00:01:00.390 に答える
2

2 つの質問をされているので、2 つの回答でお答えします。

2 番目の質問は、一度にフォーム内の 1 つの変数にアクセスするスレッドが 1 つだけであることを確認することです。

変数はフォーム上にあるため、最善の方法はSynchronizeメソッドを使用することです。

これについては、Delphi に同梱されている優れた例があります。これはthrddemo.dprプロジェクトにあります。SortThds.pasのユニットには、使用方法を示す次のメソッドがあります。

procedure TSortThread.VisualSwap(A, B, I, J: Integer);
 begin
  FA := A;
  FB := B;
  FI := I;
  FJ := J;
  Synchronize(DoVisualSwap);
 end;

幸運を、

ジェローン・プルイマーズ

于 2009-02-01T10:26:50.223 に答える