Domanda

Ricevo un'eccezione in un gestore di eventi OnTimer (TTimer) che, quando eseguito, incrementa una variabile intera nel modulo principale. I timer devono essere in grado di accedere a un numero intero incrementato utilizzato come ID.

La mia prima domanda è: come posso sapere in Delphi 2007 quale codice è in esecuzione in quale thread? Esiste un modo in modalità debug per ispezionarlo in modo che io possa determinarlo con certezza?

In secondo luogo, se devo accedere e modificare le variabili in una forma padre da un altro thread, qual è il modo migliore per farlo? A volte sembra che Delphi mi permetta di accedere a queste variabili & Quot; erroneamente & Quot; senza dare un'eccezione e altre volte dà un'eccezione.

È stato utile?

Soluzione

Solo per essere sicuri: da un lato stai parlando di un evento timer, dall'altro sul multithreading. Questi sono due modi totalmente diversi di eseguire il codice in parallelo.

Un timer verrà sempre eseguito nel thread principale. Dovrebbe essere sicuro lì per accedere a tutto ciò che è stato creato e viene utilizzato nel thread principale. In effetti, un evento timer può verificarsi solo quando non è in esecuzione alcun altro codice thread principale, poiché è necessario il gestore messaggi dell'applicazione per elaborare il messaggio timer. Quindi è al di fuori di qualsiasi codice di gestione degli eventi o quando uno dei gestori di eventi chiama Application.ProcessMessages.

Un thread è molto diverso da questo. In questo caso, il codice in thread diversi viene eseguito indipendentemente l'uno dall'altro. Se in esecuzione su una macchina multi-processore (o multi core), è anche possibile che funzionino davvero in parallelo. Ci sono alcuni problemi che potresti avere in questo modo, in particolare Delphi VCL (compreso Delphi XE incluso) non è il salvataggio dei thread, quindi le chiamate a qualsiasi classe VCL devono essere fatte solo dal thread principale (ci sono alcune eccezioni a questa regola).

Quindi, per favore, chiarisci prima se stai parlando di timer o vero multithreading, prima di aspettarti risposte utili.

Altri suggerimenti

  

Come posso dire in Delphi 2007 quale   il codice è in esecuzione in quale thread? È   c'è un modo in modalità debug per ispezionare   questo così posso determinarlo con certezza?

È possibile impostare un punto di interruzione e quando l'esecuzione si interrompe guardare la finestra di debug dei thread. Fare doppio clic su ogni thread per visualizzarne il callstack nella finestra di debug del callstack. Puoi anche utilizzare la funzione Win32 GetCurrentThreadId per scoprire il thread corrente (ad esempio per la registrazione o per determinare se il thread corrente è il thread principale, ecc.)

Dato che non stai mostrando alcun codice, è difficile essere più specifici. Solo per essere sicuri: il codice in un gestore eventi timer non viene eseguito in un thread diverso. Non avrai problemi di accesso simultaneo se stai solo usando i timer, non i thread in background reali.

  

In secondo luogo, se devo accedere e   modificare le variabili in una forma padre da   un altro thread, qual è il modo migliore   fare quello? A volte sembra   Delphi mi permette di accedervi   variabili " erroneamente " senza dare   un'eccezione e altre volte lo fa   dare un'eccezione.

Se sei davvero in un altro thread e accedi a una variabile condivisa, puoi vedere tutto ciò che accade se non proteggi quell'accesso. Potrebbe funzionare bene per la maggior parte del tempo o otterrai strani valori. Se vuoi solo modificare un numero intero in modo thread-safe, guarda InterlockedIncrement. Altrimenti potresti usare una sezione critica, mutex, monitor ... JEDI ha alcune classi utili nell'unità JclSynch per questo.

Stai ponendo due domande, quindi risponderò in due risposte.

La tua prima domanda riguarda l'uso dei TTimer; quelli vengono sempre eseguiti nel thread principale.

Molto probabilmente, la tua eccezione è una violazione di accesso.

Se lo è, di solito è causato da uno di questi:

  • a- il tuo modulo genitore è già distrutto quando il tuo TTimer spara.
  • b- non hai ancora un riferimento a il tuo modulo genitore quando il tuo TTimer incendi.

b è semplice: controlla solo se il tuo riferimento è zero .

a è più difficile e dipende da come fai riferimento al tuo modulo genitore.

Fondamentalmente vuoi assicurarti che il tuo riferimento diventi nullo quando il genitore viene distrutto o rimosso.

Se fai riferimento al tuo modulo genitore attraverso una variabile globale (in questo esempio attraverso Form2 ), allora dovresti avere TForm2 rendere la variabile Form2 zero usando l'evento OnDestroy come in questo modo:

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.

Se stai utilizzando un riferimento campo al modulo principale (come FMyForm2Reference ), allora dovresti usare aggiungi un metodo di notifica come questo:

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.

Saluti,

Jeroen Pluimers

Stai ponendo due domande, quindi risponderò in due risposte.

La tua seconda domanda è di assicurarti che solo 1 thread acceda a 1 variabile in un modulo alla volta.

Poiché la variabile si trova in un modulo, il modo migliore è utilizzare il metodo Sincronizza per questo.

C'è un eccellente esempio di ciò che viene fornito con Delphi, è nel progetto thrddemo.dpr , dove l'unità in SortThds.pas ha questo metodo che mostra come usarlo:

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

Buona fortuna

Jeroen Pluimers

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top