Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Thread Terminate (https://www.delphipraxis.net/149107-thread-terminate.html)

schweindi 14. Mär 2010 14:31


Thread Terminate
 
hallo,
ich versuche gerade einen Thread "auszuschalten" und habe schon eigentlich alles ausprobiert (Destroy, Free, Suspend, Terminate) leider kam jedes Mal ein "Access Denied" Fehler. Jetzt bin ich draufgekommen, wieso.
Das ist mein Thread, den ich schließen will, und die Pfeile markieren die Schleife, die das Problem darstellt:

Delphi-Quellcode:
type
TMonThread = class(TThread)
  private
    procedure Input;
  protected
    procedure Execute; override;
  public
    Stopped : Boolean;
    constructor Create;
    destructor Destroy; override;
    procedure DoThread(Status : Boolean);
    procedure Stop;
  end;
{...}
procedure TMonThread.DoThread(status : Boolean);
var
  Overlapped: TOverlapped;
  Signaled : DWORD;
begin
Signaled:=0;
if ComPort2.InstanceActive then
  SetCommMask(ComPort2.Handle, EV_RXCHAR) else
    begin
    Form1.Memo_sms.Lines.Add('SetCommMask not set');
    exit;
    end;
//set waiting mask
  FillChar(Overlapped, SizeOf(Overlapped), 0);
  Overlapped.hEvent := CreateEvent(nil, True, True, nil);
  WaitCommEvent(ComPort2.Handle, Signaled , @Overlapped);
  repeat               //<--------------------------------------
      sleep(readint);
      Form1.Memo_sms.Lines.Add(IntToStr(Signaled));
      Application.ProcessMessages;
  until (Signaled = EV_RXCHAR) or (Stopped = True); //<----------
  if (Signaled = EV_RXCHAR) then
    begin
    Form1.Memo_sms.Lines.Add('Input!');
    Input;
    end;
end;
{...}
procedure TMonThread.Stop;
begin
Form1.Memo_sms.Lines.Add('Thread Destroyed');
// clear buffers
SetCommMask(ComPort2.Handle, 0);
PurgeComm(ComPort2.Handle, PURGE_TXCLEAR or PURGE_RXCLEAR);
//stop thread
Stopped:= True;
end;

destructor TMonThread.Destroy;
begin
inherited Destroy;
end;
Und im Form1 (Heuptfenster) wird per Buttonklick das gemacht:

Delphi-Quellcode:
procedure TForm1.s_B_disconnectClick(Sender: TObject);
var
  InputThread : TMonThread;
begin
//stop Thread & destroy
InputThread.Stop;        //<---------------------------------
//purge buffers of port
if ComPort2.InstanceActive then
begin
ComPort2.Flush;
ComPort2.CloseSocket;
end;
Wenn die procedure Stop Aufgerufen wird, dann ändert sie zwar Stopped = True aber die Schleife merkt das garnicht!
Ich dachte "Application.ProcessMessages;" sollte das lösen....

lg

Uwe Raabe 14. Mär 2010 14:34

Re: Thread Terminate
 
Ich vermisse den Code für die Execute Methode!

schweindi 14. Mär 2010 14:55

Re: Thread Terminate
 
ahja:
Delphi-Quellcode:
procedure TMonThread.Execute;
begin
DoThread(False);
end;

procedure TMonThread.Stop;
begin
Form1.Memo_sms.Lines.Add('Thread Destroyed');
// clear buffers
SetCommMask(ComPort2.Handle, 0);
PurgeComm(ComPort2.Handle, PURGE_TXCLEAR or PURGE_RXCLEAR);
//stop thread
Stopped:= True;
end;

procedure TMonThread.Input;
var
  input,Answer : String;
begin
Input := ComPort2.RecvTerminated(readtotal,eol);
ShowMessage('" '+Input+' "');
DoThread(False);
end;
so das ist dann alles :)

Uwe Raabe 14. Mär 2010 15:09

Re: Thread Terminate
 
1. Ausser im Hauptthread sollten keine VCL-Aufrufe erfolgen (z.B. die Memo-Adds)
2. Application.ProcessMessages gehört (wenn überhaupt) in den HauptThread. Eigentlich solltest du ganz darauf verzichten.
3. Deine repeat-Schleife wird erst erreicht, wenn ein etwas empfangen wird. Den wiederholten Aufruf von DoThread hast du in der Methode Input versteckt, die immer dann aufgerufen wird, wenn ein Zeichen empfangen wurde - auch wenn Stopped = true ist!

Folge:
- solange nichts empfangen wird, erfolgt auch keine Abfrage von stopped
- obwohl stopped = true, wird weiter auf Input gewartet
- das ganze beendet sich nur bei einem anderen CommEvent als EV_RXCHAR

schweindi 14. Mär 2010 15:26

Re: Thread Terminate
 
1) die Memo Sachen habe ich nur eingebaut, damit ich sehe, was überhaupt gesendet/ empfangen wird :)
2) Die Schleife wird sofort erreicht, doch sie wird erst bei einem Inputchar (eben RXCHAR) beendet. Deshalb wollte ich eben, als zweite Bedingung (Stopped = True) einsetzen, damit ich, wenn ich zb die Verbindung zum Com Port unterbreche den Thread anhalten kann.
3) Wenn ich das Programm ausführe wird die Memo mit "Signaled : DWORD" gefüllt, eben jedes Mal kommt eine 0, da kein Char empfangen wurde - dh die Schleife wird ausgeführt.

Es soll ja nach der Procedure Stop nicht mehr auf Input gewartet werden (also schleife soll nicht mehr ausgeführt werden).
Und das dachte ich kann ich mir der Abbruchbedingung "until (Signaled = EV_RXCHAR) or (Stopped = True);" erreichen.

Uwe Raabe 14. Mär 2010 15:41

Re: Thread Terminate
 
Zitat:

Zitat von schweindi
1) die Memo Sachen habe ich nur eingebaut, damit ich sehe, was überhaupt gesendet/ empfangen wird :)

Ist aber nunmal verboten, da die VCL nicht threadsicher ist.

Zitat:

Zitat von schweindi
2) Die Schleife wird sofort erreicht, doch sie wird erst bei einem Inputchar (eben RXCHAR) beendet.

Du bekommst aber innerhalb der Schleife keinen neuen Wert für signaled - da fehlt einfach etwas.

Zitat:

Zitat von schweindi
Deshalb wollte ich eben, als zweite Bedingung (Stopped = True) einsetzen, damit ich, wenn ich zb die Verbindung zum Com Port unterbreche den Thread anhalten kann.

Das ist auch OK.

Zitat:

Zitat von schweindi
3) Wenn ich das Programm ausführe wird die Memo mit "Signaled : DWORD" gefüllt, eben jedes Mal kommt eine 0, da kein Char empfangen wurde - dh die Schleife wird ausgeführt.

Ja, aber der Wert von Signaled ändert sich nicht innerhalb der Schleife.

Zitat:

Zitat von schweindi
Es soll ja nach der Procedure Stop nicht mehr auf Input gewartet werden (also schleife soll nicht mehr ausgeführt werden).
Und das dachte ich kann ich mir der Abbruchbedingung "until (Signaled = EV_RXCHAR) or (Stopped = True);" erreichen.

Schon, aber der Aufruf von Input wird nicht durch Stopped verhindert und da rufst du DoThread wieder auf und der Zirkus geht weiter.

HERMES 14. Mär 2010 16:15

Re: Thread Terminate
 
Wenn du in deinem Formular mit diesem code arbeitest, dann wird in deiner s_B_disconnectClick Methode ein anderes TMonThread Objekt verwendet als in den anderen Methoden, somit hat der aufruf von Stop keine Auswirkung auf dein anderes Thread Objekt, das irgendwo anderst erzeugt und gestartet wurde.

Uwe Raabe 14. Mär 2010 16:19

Re: Thread Terminate
 
Zitat:

Zitat von HERMES
Wenn du in deinem Formular mit diesem code arbeitest, dann wird in deiner s_B_disconnectClick Methode ein anderes TMonThread Objekt verwendet als in den anderen Methoden, somit hat der aufruf von Stop keine Auswirkung auf dein anderes Thread Objekt, das irgendwo anderst erzeugt und gestartet wurde.

Soweit hatte ich noch gar nicht gelesen, aber das geht natürlich so wirklich nicht.

schweindi 14. Mär 2010 16:51

Re: Thread Terminate
 
okay...

1) ich habe es gerade nochmal ausprobiert: Wenn die Schleife läuft ist natürlich Signaled auf 0 dann gebe ich im Hyperterm irgendwas ein dann ist die Schleife Fertig (Signaled = EV_RXCHAR) und dann ruft er input auf. Also das "WaitCommEvent(ComPort2.Handle, Signaled, @overlapped);" ändert sofort Signaled, da es Input gibt.

2) Memos sind draußen

3) wie kann ich per Buttonklick genau dem Thread sagen, er soll zb Suspended werden?

HERMES 14. Mär 2010 17:50

Re: Thread Terminate
 
Du musst die Threadvariable als Klassenmember deiner Formularklasse deklarieren und alle Deklarationen als lokale Variable entfernen.

Edit: warscheinlich hast du InputThread in deiner Klasse deklariert, also lasse einfach das

Delphi-Quellcode:
var
 InputMon:T...Thread;
weg


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:38 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz