Programm beenden erkennen - im Hintergrund

Rund um die LCL und andere Komponenten
Antworten
Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Programm beenden erkennen - im Hintergrund

Beitrag von Timm Thaler »

Ich habe ein Konsolenprogramm mit folgender Struktur im Hauptprogramm:

Code: Alles auswählen

begin
  InitProg()// <- hier Start in Logfile schreiben
  repeat
    MachWas();
    sleep(10);    // alle 10msec
    if KeyPressed then    //  Taste prüfen
      if ReadKey = ^C then     // wenn Ctrl-C
        Break;
  until false;
  CloseProg()// <- hier Ende in Logfile schreiben
end.         


Starte ich das Programm in der Konsole, kann ich es mit Ctrl-C beenden, und es schreibt brav Start und Ende ins Logfile.

Starte ich das Programm allerdings mit cron beim Start des Raspberry, habe ich ja keinen Zugriff per Ctrl-C. Ich kann das Programm entweder killen oder es wird gekillt, wenn ich den Raspi runterfahre. Beide Male wird das Ende aber natürlich nicht im Logfile vermerkt.

Gibt es eine Möglichkeit, das Programm im Hintergrund laufen zu lassen, es aber dennoch per Konsole ordentlich zu beenden bzw. bei Shutdown eine Beenden-Nachricht zu erhalten? Wie wird das bei Services gemacht, da gibt es auch start service und stop service?

Idealerweise soll das Programm
- über die Konsole beendet werden können
- beim Herunterfahren sauber beendet werden
- durch einen Cron Job täglich beendet und neu gestartet werden

Realisierbar? Mit vertretbarem Aufwand realisierbar?

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Programm beenden erkennen - im Hintergrund

Beitrag von Warf »

Du könntest eine Pipe verwenden z.B.

Code: Alles auswählen

program Project1;
 
{$mode objfpc}{$H+}
 
uses
  BaseUnix;
 
function StreamLength(Stream: cint): cint; inline;
begin
  FpIOCtl(Stream, 1074030207, @Result);
end;
 
var inStream: cint;
  c: Char;
begin
  if FpMkfifo(PChar('./test.pipe'), &0666) <> 0 then exit;
  try
    inStream := FpOpen(PChar('./test.pipe'), O_RDONLY);
    if inStream = 0 then exit;
    while True do
    begin
      if (StreamLength(inStream) > 0) And
      (FpRead(inStream, c, 1) = 1) And
      (c='q') then
        exit
    end;
 
  finally
    FpClose(inStream);
    FpUnlink(PChar('./test.pipe'));
  end;
end.
 
 


Dieses Programm läuft so lange bis q in die Pipe geschrieben wird. Zum beenden dann einfach

Code: Alles auswählen

echo q > test.pipe

verwenden.

Optimaler wäre es natürlich das Interrupt Signal SIGINT abzufangen. Ich bin mir nicht sicher aber ich glaube die TCustomApplication Klasse kann das behandeln.

Am besten wäre es einen Daemon zu schreiben, schön hier erklärt: http://wiki.freepascal.org/Daemons_and_Services. Wenn die Anwendung immer im Hintergrund laufen soll ist das genau was du suchst.

braunbär
Beiträge: 369
Registriert: Do 8. Jun 2017, 18:21
OS, Lazarus, FPC: Windows 10 64bit, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: 64Bit
Wohnort: Wien

Re: Programm beenden erkennen - im Hintergrund

Beitrag von braunbär »

Wenn ein Programm ordnungsgemäß herutergefahren wird, werden doch die finalization Abschnitte der verschiedenen Programmunits durchlaufen.
In so einen Abschnitt den Aufruf von Closeprog setzen, dann wird es ausgeführt, egal, wodurch die Programmbeendigung erfolgt.

Du musst nur darauf achten, dass die Units im uses in der richtigen Reihenfolge angegeben werden, dein closeprog muss aufgerufen werden, bevor die finalization von anderen Units, die dein closeprog braucht, schon erfolgt ist.

P.S. Ich habe mich noch nie mit Konsolenprgrammen beschäftigt, aber kann man nicht sogar direkt in der Hauptunit eines Konsolenprogramms einen initialization und einen finalization Abschnitt definieren?

Timm Thaler
Beiträge: 1224
Registriert: So 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
CPU-Target: Raspberry Pi 3

Re: Programm beenden erkennen - im Hintergrund

Beitrag von Timm Thaler »

Das mit den Daemons gefällt mir. Ist wahrscheinlich die sauberste Lösung.

Unter http://wiki.freepascal.org/Daemons_and_Services steht:

Stop
Called when daemon should stop. This method must return immediately with True.
Shutdown
Called when daemon should be killed. This method must stop the daemon immediately and return with True. This is not triggered under Linux. Linux simply kills the daemon.


Wenn ich den Raspberry neu boote, wird dann Stop oder Shutdown ausgeführt? Bei Shutdown => kill hätte ich ja nix gewonnen, denn ein Logfile-Eintrag wird nicht erzeugt und eventuell gerade offene Dateien nicht geschlossen.

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Programm beenden erkennen - im Hintergrund

Beitrag von Warf »

Timm Thaler hat geschrieben:Das mit den Daemons gefällt mir. Ist wahrscheinlich die sauberste Lösung.

Unter http://wiki.freepascal.org/Daemons_and_Services steht:

Stop
Called when daemon should stop. This method must return immediately with True.
Shutdown
Called when daemon should be killed. This method must stop the daemon immediately and return with True. This is not triggered under Linux. Linux simply kills the daemon.


Wenn ich den Raspberry neu boote, wird dann Stop oder Shutdown ausgeführt? Bei Shutdown => kill hätte ich ja nix gewonnen, denn ein Logfile-Eintrag wird nicht erzeugt und eventuell gerade offene Dateien nicht geschlossen.


Keine Ahnung, solltest du am besten einfach mal ausprobieren, würde mich auch interessieren.

Antworten