Announcement

Collapse
No announcement yet.

Hauptprogramm wartet sich an WaitFor zu tode

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hauptprogramm wartet sich an WaitFor zu tode

    Hallo Leute!

    Ich habe ein kleines Problem mit grossen Folgen:

    In meiner Applikation greife ich von drei Threads aus auf Daten in einer SPS-Steuerung zu. Das ganze funktioniert bis zu dem Zeitpunkt wo der Benutzer das Programm beenden möchte noch ganz gut. Aber beim Beenden über Terminate werden bloss zwei der drei Threads korrekt beendet. Der dritte kommt dann nicht in seinem OnTerminate-Event an. Das Programm scheint in der WaitFor-Zeile stehen zu bleiben.

    Das kuriose daran ist, das dieses Phänomen in Abhängigkeit vom Zeitpunkt des Beendens (Klick des Users) zu stehen scheint.

    Jetzt kommt der vereinfachte Quellcode, der vom Aufbau her für alle drei Threads gleich ist.

    /////////////////////////////////////////////

    type TBDErfThread = class (TThread)
    private
    FEvent : THandle;
    Thread_Anzeige : TStatusBar;
    str_AnzeigeText : String;
    c_WaitTime: Cardinal;
    i_proz : Integer;
    procedure Work();
    procedure RefreshStatus();
    procedure ThreadEnd(Sender : TObject);
    protected
    procedure Execute; override;
    public
    constructor Create(Anzeige : TStatusBar);
    procedure TerminateEx;
    procedure SetWaitTime(c_NewWaitTime : Cardinal);
    end;

    constructor TBDErfThread.Create(Anzeige : TStatusBar);
    begin
    inherited Create(TRUE);
    FreeOnTerminate := TRUE;
    OnTerminate := ThreadEnd;
    Thread_Anzeige := Anzeige;
    SetWaitTime(1000 * 5);
    Resume();
    end;

    procedure TBDErfThread.TerminateEx;
    begin
    Thread_Anzeige.Panels[2].Text := 'Terminate BDE-Thread...';
    Synchronize(Thread_Anzeige.Refresh);
    Terminate;
    end;

    procedure TBDErfThread.Execute;
    begin
    FEvent := CreateEvent(nil, False, False, nil);
    try
    // Loggen ('Execute...1');
    while not Terminated do
    begin
    if WaitForSingleObject(FEvent, c_WaitTime) = WAIT_OBJECT_0 then break;
    // Loggen('Execute...2');
    Synchronize(Work);
    end;
    finally
    // Loggen('Execute...3');
    CloseHandle(FEvent);
    end;
    end;

    procedure TBDErfThread.Work();
    begin
    // Auf Benutzer reagieren
    Application.ProcessMessages;

    // Daten aus SPS holen, verarbeiten und in Datenbank ablegen
    end;

    procedure TBDErfThread.SetWaitTime(c_NewWaitTime : Cardinal);
    begin
    c_WaitTime := c_NewWaitTime;
    end;

    procedure TBDErfThread.ThreadEnd(Sender: TObject);
    var
    str_Msg : String;
    begin
    //Loggen('TBDErfThread.ThreadEnd wurde ausgeführt...');
    arr_Threads.Delete(arr_Threads.IndexOf(BDErfThread ));
    end;

    ////// Im Hauptprogramm
    var
    arr_Threads : TList; // global definiert

    // Beim Start des Programms
    begin

    arr_Threads := TList.Create();

    // Erstellen und starten des Thread 1
    if STErfThread = nil then
    begin
    // erstellen und starten
    STErfThread:= TSTErfThread.Create(frm_Hauptmenue.stb_Status1);
    arr_Threads.Add(STErfThread);
    end;

    // Erstellen und starten des Thread 2
    if BDErfThread = nil then
    begin
    // erBDEllen und starten
    BDErfThread := TBDErfThread.Create(frm_Hauptmenue.stb_Status2);
    arr_Threads.Add(BDErfThread);
    end;

    // Erstellen und starten des Thread 3
    if VerfErfThread = nil then
    begin
    // erstellen und starten
    VerfErfThread := TVerfErfThread.Create(frm_Hauptmenue.stb_Status3);
    arr_Threads.Add(VerfErfThread);
    end;

    end;

    // Beim Beenden des Programms
    begin
    // STErf-Thread 1 beenden
    if STErfThread <> nil then
    begin
    STErfThread.TerminateEx;
    end else
    begin
    // Nichts tun, da Thread schon nicht mehr da...
    end;

    // Thread 2 beenden
    if BDErfThread <> nil then
    begin
    BDErfThread.TerminateEx();
    end else
    begin
    // Nichts tun, da Thread schon nicht mehr da...
    end;

    // Thread 3 beenden
    if VerfErfThread <> nil then
    begin
    VerfErfThread.TerminateEx;
    end else
    begin
    // Nichts tun, da Thread schon nicht mehr da...
    end;

    while arr_Threads.Count <> 0 do
    begin
    //
    Item := arr_Threads.First;
    if Item <> nil then
    begin
    Item.WaitFor;
    Item := nil; // nur zur Sicherheit
    end;
    end;

    // weiter aufräumen
    end;

    /////////////////////////////////////////////

    Ich bin für jeden Hinweis dankbar!
Working...
X