Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi TThread mit WaitForMultipleObjects in DLL arbeitet nicht ? (https://www.delphipraxis.net/11876-tthread-mit-waitformultipleobjects-dll-arbeitet-nicht.html)

Rumpi 15. Nov 2003 18:21


TThread mit WaitForMultipleObjects in DLL arbeitet nicht ?
 
Hallo,
Delphi-Quellcode:

unit cl_Thread;

interface
  uses Windows, Classes, syncobjs, Sysutils;

type

  TTimerThread = class(TThread)
  private
    { Private-Deklarationen }
    FEnabled    : Boolean;
    FOneSec     : Boolean;
    FOnNotify   : TNotifyEvent;
    FInterval   : Longint;
    FTag        : Longint;
    FCloseEvent : TSimpleEvent;
    FEnableEvent : TSimpleEvent;
    FLastSec    : Word;
  public
    constructor Create( OnNotify: TNotifyEvent ); overload;
    constructor Create( aInterval: Longint; OnNotify: TNotifyEvent ); overload;
    destructor Destroy; override;
    procedure  Stop;
  protected
    procedure Execute; override;
    procedure Notify;
    procedure SetEnabled( Value: Boolean );
    procedure SetInterval( Value: Longint );
  published
    property Interval: Longint read FInterval write SetInterval;
    property Enabled : Boolean read FEnabled write SetEnabled;
    property Tag    : Longint read FTag write FTag;
  end;

implementation

constructor TTimerThread.Create( OnNotify: TNotifyEvent );
begin
  inherited Create( True );
  FreeOnTerminate := True;
  FOnNotify    := OnNotify;
  FInterval    := 50;
  FCloseEvent  := TSimpleEvent.Create;
  FEnableEvent := TSimpleEvent.Create;
  FEnabled     := True;
  FOneSec      := True;
  Resume;
end;

constructor TTimerThread.Create( aInterval: Longint; OnNotify: TNotifyEvent );
begin
  inherited Create( True );
  FreeOnTerminate := True;
  FOnNotify  := OnNotify;
  FInterval  := aInterval;
  FCloseEvent := TSimpleEvent.Create;
  FEnableEvent:= TSimpleEvent.Create;
  FEnabled   := False;
  FOneSec    := False;
  Resume;
end;

destructor TTimerThread.Destroy;
begin
  FCloseEvent.Free;
  Inherited Destroy;
end;

procedure TTimerThread.Execute;
var
  Signaled   : Integer;
  h, m, s, ms : Word;
  EventHandles: array[0..1] of THandle;
begin
  EventHandles[0] := FCloseEvent.Handle;
  EventHandles[1] := FEnableEvent.Handle;
  repeat
    Signaled := WaitForMultipleObjects( 2, @EventHandles, False, FInterval );
    case Signaled of

      // Close event, terminate the thread
      WAIT_OBJECT_0 :
        begin
          ResetEvent(FCloseEvent.Handle);
          Break;
        end;

      WAIT_OBJECT_0 + 1:
        begin
          ResetEvent(FEnableEvent.Handle);
          FEnabled := True;
        end;

      //
      WAIT_TIMEOUT :
        if Not FOneSec then
          Synchronize(Notify)
        else
        begin
          // Has a second passed ?
          DecodeTime( Now, h, m, s, ms );
          if s <> FLastSec then
          begin
            //Notify;
            Synchronize(Notify);
            FLastSec := s;
          end;
        end;

    end;
  until Terminated;
end;

procedure TTimerThread.Notify;
begin
  if Assigned( FOnNotify ) and FEnabled then
    FOnNotify( Self );
end;

procedure TTimerThread.Stop;
begin
  FEnabled := False;
  SetEvent(FCloseEvent.Handle);
end;

procedure TTimerThread.SetEnabled( Value: Boolean );
begin
  if FEnabled <> Value then
    if Value then
      SetEvent(FEnableEvent.Handle)
    else
      FEnabled := False;
end;

procedure TTimerThread.SetInterval( Value: Longint );
begin
  if FEnabled then
  begin
    FEnabled := False;
    FInterval := Value;
    SetEvent(FEnableEvent.Handle);
  end
  else
    FInterval := Value;
end;


end.

TTimerThread funtioniert solange man ihn aus einer Application startet,
aber nicht in einer DLL :shock: ... Warum :gruebel: ?

Bleibt bei WaitForMultipleObjects stehen obwohl ein Interval gesetzt ist :wall: !

Ich musste also wieder zu TTimer :cry: greifen, aber ich würde gerne
TTimerThread auch in DLL's verwenden wollen.

Kann mir das mal einer erklären :?:

mfg Rumpi

Rumpi 15. Nov 2003 20:51

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Kann mir keiner Helfen ?

mfg Rumpi

[edit=Daniel B]Doppelpost gelöscht. Mfg, Daniel B[/edit]
[edit=Daniel B]BB-Code wieder eingeschaltet. Mfg, Daniel B[/edit]

Christian Seehase 15. Nov 2003 20:59

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Moin Rumpi,

:warn:

findest Du es nicht auch reichlich übertrieben, nach 2,5 Stunden Deinen Thread zu pushen?

Rumpi 15. Nov 2003 21:10

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
So war das nicht gemeint. :shock:
Das ist nur eine Frage und kein Pushen. :?

mfg Rumpi

Sharky 15. Nov 2003 21:13

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Hai Rumpi,

ich bin mir sicher das jemand antwortet wenn er die Antwort kennt.

Pushen (ob mit absicht oder nicht) innerhalb von weniger als 24h ist halt nicht die feine Art.

Bernd Ua 15. Nov 2003 22:17

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Hi ungeduldiger,

so ausm Bauch - schau dir mal an, ob in der DLL die Varaible IsMultiThread auf true gesetzt
ist oder nicht und setze sie ansonsten auf true.

Dein Timer ist übrigens ein toller Plan - denk aber daran, dass das reale Intervall
gleich "eingestelltes Intervall + Ausführungszeit Eventhandler" ist, da Dein Synchronize
den Thread anhält

Bernd

Rumpi 15. Nov 2003 22:49

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Vielen Danke Bernd für den Input,

Ich habe die Variable auf True gesetzt aber es tut sich nix.
Es ist echt komisch, alle anderen Threads mit WaitForMultipleObjects
ohne einen TimeOut gehen ja ( Lesen einer RS232 EventFlags ).

Ich versuche Timer so gut es geht zu meiden.

Danke für deinen Hinweis mit Synchonize( X ),
bei meinen Funktionen ist das genau so gewollt,
der TimerThread soll erst danch wieder den Intervall starten.

mfg Rumpi

Luckie 16. Nov 2003 03:47

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Zitat:

Zitat von Bernd Ua
so ausm Bauch - schau dir mal an, ob in der DLL die Varaible IsMultiThread auf true gesetzt
ist oder nicht und setze sie ansonsten auf true.

Sollte eigentlich überflüssig sein, da er die VCL Thread-Klasse benutzt. Beim erzeugen des Threads wir die Variable automatisch auf True gesetzt. Man muss es nur von Hand machen, wenn man die API Funktion CreateThread ohne den Delphi Wrapper BeginThread benutzt. :wink:

Bernd Ua 16. Nov 2003 09:39

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Moin Rumpi,

jetzt bin ich ein bisschen wacher :)

Eigentlich sollte nix dagegen sprechen, dass WaitForMultipleObjects auch in DLLs
funktioniert. Interessehalber habe ich deinen Thread mal in ein Projekt kopiert und
aus ner DLL laufen lassen. Da hängt sich nix auf und bleibt nix stehen.

Das dumme ist, dass in Deinem Profil und der frage nix zur Delphi Version steht
(... und dass ich normalerweise Synchronize meide <g>).

Die Implementierung von Synchronize hat sich zwischen D5 und D6 geändert ( wg Crossplatform).

Fall D5 oder kleiner :
Bei D5 stellt Synchronize eine Nachricht mit einem Pointer auf den Thread in die
Nachrichtenschleife der Applikation (CM_EXECPROC) die zu einem Deadlock führt,
wenn die Applikation im Haupthread gerade auf irgendwas mit WaitForMultipleObjects wartet
( einer der Gründe warum ich Synchronize meide :zwinker: )
Ersetze dann mal spasseshalber Dein WaitForMultipleObjects durch MsgWaitForMultipleObjects !

Fall D6 oder höher
Synchronize erzeugt ein Event und stellt das Event in eine globale Variable namens SyncList ein (Unit Classes)
die bei GUI Applikationen automatisch ansonsten manuell über CheckSynchronize geprüft werden kann.
Hier haben DLL und EXE zweimal die globale Variable SyncList, dummerweise bleibt die Synclist der Exe immer leer
und Dein Event wird nie gerufen.
Workaround hier: Aktiviere bei EXE und DLL Runtimepackages ( rtl sollte reichen)

Grüsse Bernd

@Luckie: war nicht mehr richtig wach gestern

Rumpi 16. Nov 2003 11:54

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Hi Bernd,

... vorab schon mal Danke :)

Zitat:

Zitat von Bernd Ua
Das dumme ist, dass in Deinem Profil und der frage nix zur Delphi Version steht
(... und dass ich normalerweise Synchronize meide <g>).

Ich verwende D6 und D7 ( manchmal auch noch D4 oder D1 ) sorry werde ich das nächste Mal angeben.

Zitat:

Zitat von Bernd Ua
Synchronize erzeugt ein Event und stellt das Event in eine globale Variable namens SyncList ein (Unit Classes)
die bei GUI Applikationen automatisch ansonsten manuell über CheckSynchronize geprüft werden kann.
Hier haben DLL und EXE zweimal die globale Variable SyncList, dummerweise bleibt die Synclist der Exe immer leer
und Dein Event wird nie gerufen.
Workaround hier: Aktiviere bei EXE und DLL Runtimepackages ( rtl sollte reichen)

Ich habe nur im TimerThread Synchronize weggelassen und schon gings :-D
Delphi-Quellcode:
  // Synchronize( Notify ); //  so gehts nur wenn in einer EXE
  Notify;                   //  und schon gehts auch in der DLL
                             //  hatte ich ja schon als Alternative im code
Ich musste "nicht" in der EXE und oder der DLL Runtimepackages aktivieren :gruebel:

Danke noch einmal Bernd.

mfg Rumpi

Bernd Ua 16. Nov 2003 12:21

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Zitat:

Ich habe nur im TimerThread Synchronize weggelassen und schon gings
So war das nicht gemeint, mit nicht verwenden!!!!!

Dein Eventhandler im Hauptprogramm läuft dann im aufrufenden Thread und das
wirst Du früher oder später bereuen ! Lass es sein !

das Chaos ist dann nicht mehr zu managen - weil Du nach kurzer Zeit nicht mehr weisst,
was in welchem Threadkontext läuft. Und Zugriff auf VCL-Klassen aus mehreren Threads wird
knallen !
Dasselbe gilt im übrigen für Deine published properties
( mal abgesehen davon, dass published bei Klassen die nicht
TPersistent abstammen oder {$M+} verwenden eh unsinnig ist).

Ein Zugriff die Properties deiner Klasse während der Thread läuft,
ist nur auf einer Ein-Prozessor-Maschine relativ gefahrlos möglich.
Auf einem Mehrprozessorsystem ( oder auch einer neuen Intel CPU mit aktiviertem
Hyperthreading !!) sind Intergeroperationen nicht atomar!
Verwende mindestens die InterLockedxxxx Funktionen des OS für die
Eigenschaftsimplementierung oder kapsele die Datenfelder des Threads.

Bernd

Rumpi 16. Nov 2003 15:25

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Hallo Bernd

Zitat:

Zitat von Bernd Ua
So war das nicht gemeint, mit nicht verwenden!!!!![/b]

Dein Eventhandler im Hauptprogramm läuft dann im aufrufenden Thread und das
wirst Du früher oder später bereuen ! Lass es sein !
Bernd

Danke für den Hinweis, da brennt bei mir jedoch schon seit Jahren nix mehr an!
- CriticalSection
- Mutex
- ThreadList

Das UI ist in meinen Anwendungen "mittlerweile" austauschbar.

Genau das mache ich zum Beispiel in der DLL, die muss sich
um die Hardware und die interne Verwaltung (Optionen) kümmern.
Mein Kollege hängt sich da mit dem CBuilder 6 ein.

Mein UI kann sogar parallel eingreifen es geht sogar soweit,
dass man sich mit einem UI auf einem anderen
PC im Netzt via IP einloggen kann und die Oberfläche
synchronisiert sich.

Die Leute in unserer Fa. haben echt Bauklötze gestaunt
als sich unsere Hardware das erste mal
zum Einen Lokal und zum Anderen im Netz parallel steuern ließ!


mfg Rumpi

Rumpi 17. Nov 2003 15:22

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Delphi-Quellcode:

destructor TTimerThread.Destroy;
begin
  FCloseEvent.Free;
  FEnableEvent.Free; // ups hatte ich vergessen
  Inherited Destroy;
end;
mfg Rumpi

negaH 18. Nov 2003 08:16

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Also, ich verstehe auch nicht was sich technisch mit deinem TimerThread gegenüber einem TTimer verbessern sollte. Durch das Synchronize() machst du die Vorteile eines Threads gegenüber einem TTimer kaputt, und verschlimmbesserst sogar noch die Gesamtstabilität der Anwendung. Ausserdem sind Threads nicht resourcenschonender als Timer. Ein Timer benötigt zwar ein Window Handle, dafür benötigen Threads während ihrer aktiven Phase und dem Contextswitch mehr Resourcen. Betrachten auf die Zeitresolution sind Threads auch nicht besser als Timer. Beide können nur runter bis auf 1 ms, und sind unterhalb 50 ms nicht mehr exakt.

Nur falls der Thread ohne Synchronize() auskäme würde man einen Vorteil erlangen.

Gruß Hagen

Rumpi 18. Nov 2003 09:08

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Hi Hagen,

vielen Dank für deinen Hinweis,
genau das "Synchronize" war ja auch das Deadlock Problem in der DLL.
Du siehst am Code das ich
Delphi-Quellcode:
//Notify;
schon stehen hatte.
Ich werde noch FSyncMode dazu fügen.

Der Vorteil für mich ist "nicht nur", dass ich den TTimerThread nur mit
einer Zeile erzeuge
Delphi-Quellcode:
 FTimerThread := TTimerThread.Create( Interval, Notify );
und auch nur mit einer wieder
Delphi-Quellcode:
  FTimerThread.Stop;
freigebe.

Desweiteren verwende ich ihn auch um ein/mehrer (MuliMonitor) UI's jede Sekunde (+- 50ms)
Delphi-Quellcode:
  FTimerThread := TTimerThread.Create( Notify );
zu updaten ( siehe FOneSec ).

In einem Programm laufen davon mehr als 10
- Unabhängige Hardware Connects ( Seriell )
- Unabhängige Hardware State Checks
- Unabhängige IP Re/Connects Client seitig
- ...

ca. 10-20 Threads, noch nicht einmal die Hardware
Threads der Seriellen oder SaredMemory Kommunikation
dazu gerechnet. Es ist wirklich ein ganzer
"Batzen an TTimer nötig" ... und die kann man nun mal
nur Begrenzt verwenden, oder?

Jeder kann für sich entscheiden ob er
einen Thread anstelle eines TTimers verwendet.

Klar ist wohl auch jedem, dass ich in der
Anwendung alles Threadsicher halten muss.
Mit diesem Gedanken gehe ich seit D2 immer
an ein Projekt, es ist für mich einfacher
sofort CriticalSection's ( ob nun Global oder Local),
Mutex und ThreadList's zu arbeiten.
Schon wegen der nicht Synchron arbeitenden Hardware ( siehe oben )
und den multiplen Steuerungsmöglichkeiten.
z.B.
- Mehrfach Local als MultiMonitor
( mit eigenem TouchScreen Funktionen ohne System Treiber,
so das du eine Maske auf Screen 2 bedienen kannst und
parallel auf Screen 1 mit der Maus fuchtel kannst um
eine andere Maske zu bedienen )
- Mehrfach Dezentral im Netz

... und es Funktioniert!

Was immer noch offen ist:

Warum der Deadlock in einer DLL wenn ich
Delphi-Quellcode:
Synchronize( FNotify );
verwende?

Vielen Dank noch einmal Hagen.
Für jeden Input dankbar! (No.5 lebt :-D )

mfg Rumpi No.5

negaH 26. Nov 2003 12:24

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Wenn soviele Timer nötig sind, dann ist es besser nur einen einzigsten "Multi-Timer-Thread" zu programmieren. Man nimmt also einen einzigsten Thread der aber eine Liste von Intervallen verwaltet. Nun berechnet er ausgehend von diesen Intervallen die Dauer in Millisekunden bis zum nächsten Ereigniss. Angenommen drei Intervalle 100ms und 500ms. Der Thread wartet immer 100ms und lösst das 100ms Ereignis aus, alle 5 mal das 500ms Ereignis. Einen solchen Timer-Thread habe ich selber schon gecodet.
Vorteil dabei ist das alle Ereignisse zueinander "synchrone" sind, d.h. sie überschneiden sich nicht in deren Ausführung.

Gruß Hagen

negaH 26. Nov 2003 12:25

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Wenn soviele Timer nötig sind, dann ist es besser nur einen einzigsten "Multi-Timer-Thread" zu programmieren. Man nimmt also einen einzigsten Thread der aber eine Liste von Intervallen verwaltet. Nun berechnet er ausgehend von diesen Intervallen die Dauer in Millisekunden bis zum nächsten Ereigniss. Angenommen drei Intervalle 100ms und 500ms. Der Thread wartet immer 100ms und lösst das 100ms Ereignis aus, alle 5 mal das 500ms Ereignis. Einen solchen Timer-Thread habe ich selber schon gecodet.
Vorteil dabei ist das alle Ereignisse zueinander "synchrone" sind, d.h. sie überschneiden sich nicht in deren Ausführung.

Gruß Hagen

Rumpi 26. Nov 2003 12:51

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
Hi Hagen,

danke für den Tip, ich werde eine NotifyChain in die classe aufnehmen.
Geht bei meinen Anwendungen aber leider nicht.


mfg Rumpi

the_Sisyphos 9. Dez 2003 06:49

Re: TThread mit WaitForMultipleObjects in DLL arbeitet nicht
 
noch eine kleine Anmerkung nebenbei zu WaitForMultipleObjects über die ich beim Programmieren eines IP Scanners gestolpert bin .. diese Funktion kann nur mit maximal MAXIMUM_WAIT_OBJECTS Threads umgehen und dies sind (zumindest unter Delphi 6) 64 Stück. Wobei man zudem bedenken sollte das scheinbar diese Zahl die Gesamtzahl an Threads ist die Delphi ohne Probleme verwalten kann. Nachdem das Hauptprogramm auch in einem eigene läuft reduziert sich somit die maximal verfügbare Anzahl mit jedem weiteren Thread der sonst noch neben dem Hauptprogram läuft.

Das heißt NICHT das Delphi nicht mehr TThreads aufmachen kann, aber das heißt das die Funktion WaitForMultipleObjects ab sofort nurnoch -1 zurück liefert, also weder WAIT_OBJECT_0, WAIT_TIMEOUT noch WAIT_FAILED zurückliefert!!! Das heißt aber auch das bei einem normalen Programmfluß in dem das nicht abgefangen wird, das Programm schlicht weiter läuft anstatt stehen zu bleiben was unschöne Effekte haben kann.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:53 Uhr.

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