hansi: Perl gleichzeitiger Dateizugriff

Hallo an alle,

Bei meinem Skript besteht die Möglichkeit/Gefahr, daß mehrere User dieses Skript gleichzeitig aufrufen. Dabei werden Werte gelesen und geschrieben.

Nun besteht ja die Möglichkeit, daß ein User die Datei in beschlag hat und gerade in diese Datei schreibt, und gleichzeitig ein anderer User diese Datei aber lesen möchte.

Was passiert in diesem Fall. Das Script ist in Perl geschrieben. Das Script läuft auf einem Linuxsystem. Als Webserver wird Apache 1.3 verwendet.

Ich habe versucht eine deutsche Beschreibung für den Befehl lock und unlock zu finden, leider ohne Erfolg. Soviel ich im englischen verstanden habe handelt
es sich bei diesem Befehl um eine mögliche Lösung. Die Frage ist dann natürlich auch, ist dieser Befehl überhaupt wichtig oder bedarf es überhaupt einer besonderen Behandlung.

Es gibt leider kein Beispiel im Netz, da ich bei mir einen Webserver zum testen aufgebaut habe. Meine Seiten sind noch nicht öffentlich.

Im voraus schon mal Danke für eure Antworten.
Hansi

  1. Hi,

    Bei meinem Skript besteht die Möglichkeit/Gefahr, daß mehrere User dieses Skript gleichzeitig aufrufen. Dabei werden Werte gelesen und geschrieben.

    Nun besteht ja die Möglichkeit, daß ein User die Datei in beschlag hat und gerade in diese Datei schreibt, und gleichzeitig ein anderer User diese Datei aber lesen möchte.

    Was passiert in diesem Fall.

    die zweite Instanz liest leere Daten, während die erste gerade speichert, und speichert dieselben später ab. Die Daten gehen also verloren.

    Ich habe versucht eine deutsche Beschreibung für den Befehl lock und unlock zu finden, leider ohne Erfolg. Soviel ich im englischen verstanden habe handelt
    es sich bei diesem Befehl um eine mögliche Lösung. Die Frage ist dann natürlich auch, ist dieser Befehl überhaupt wichtig oder bedarf es überhaupt einer besonderen Behandlung.

    Du meinst vermutlich flock? Die Beschreibung dazu findest Du bei der bei Perl mitgelieferten Doku. Unter Windows in der HTML-Doku perlfunc, unter Unix schneller mit
    perldoc -f flock

    Ich habe die Sache übrigens sehr umständlich gelöst (weil ich flock selber nicht richtig verstehe *g*), indem ich vor jedem Schreibzugriff eine Dummy-Datei anlege, die sozusagen als Markierung dient. Vor jedem Lesezugriff prüfe ich in einer while-Schleife, ob diese Datei existiert. Vorsicht, es kann zu einer Endlosschleife führen, deshalb prüfe nur z.B. 10 mal und warte dazwischen mit select(undef,undef,undef,0.1) eine Zehntelsekunde (z.B.).

    Cheatah

    1. Hallo,

      auch hier möchte ich Dir erst einmal danken. Ich habe auch diese Geschichte mal ausprobiert. Und möchte auch hier das Resultat kurz darstellen.

      die zweite Instanz liest leere Daten, während die erste gerade speichert, und speichert dieselben später ab. Die Daten gehen also verloren.

      Das ist ja katastrophal. Jetzt weiß ich wenigstens warum mir letzten eine Datei auf Null gesetzt wurde.

      Du meinst vermutlich flock? Die Beschreibung dazu findest Du bei der bei Perl mitgelieferten Doku. Unter Windows in der HTML-Doku perlfunc, unter Unix schneller mit

      stimmt natürlich.

      perldoc -f flock

      ich bin Linux-Neuling und total Windowsverseucht. Deshalb danke auch für diesen Tip. Hier jetzt allerdings ein Loblied auf Linux zu singen, würde wohl den Rahmen sprengen.

      Ich habe die Sache übrigens sehr umständlich gelöst (weil ich flock selber nicht richtig verstehe *g*)[...]

      Da bin ich aber beruhigt, daß auch ein Profi!? seine Schwächen eingesteht.

      [...], indem ich vor jedem Schreibzugriff eine Dummy-Datei anlege, die sozusagen als Markierung dient. Vor jedem Lesezugriff prüfe ich in einer while-Schleife, ob diese Datei existiert. Vorsicht, es kann zu einer Endlosschleife führen, deshalb prüfe nur z.B. 10 mal und warte dazwischen mit select(undef,undef,undef,0.1) eine Zehntelsekunde (z.B.).

      Die Idee ist famous. ich habe deshalb eine kleine Funktion erstellt, die genau das macht.

      sub waittofileclose
        {
        $f = $_;
        $isopen = "$filename.isopen";
        $testagain = 0;
        while ($testagain < 20)
          {
          if (open (TESTFILE, "$isopen"))
            {
            close (TESTFILE);
            select(undef,undef,undef,0.1);
            $testagain++;
            }
          else
            {
            $testagain = 20;
            open (TESTFILE, ">$isopen");
            close (TESTFILE);
            }
          }
        }

      Diese Funktion rufe ich vor dem eigentliche öffenen der eigentlichen zu bearbeitenden Datei auf. Wenn ich dann alle Aktionen an der Hauptdatei durchgeführt habe, lösche ich die Kontrolldatei mit dem Befehl unlink $isopen;
      Sollte nun ein anderer Prozess in einer Warteschleife stecken, merkt dieser ja, daß die Datei entfernt wurde und kann nun seine Arbeiten durchführen. usw.

      Vielleicht kann man ja noch alle 10 oder 100 Aufrufe ein Backup der Datendatei anlegen. Natürlich nur, wenn die Datendatei nicht die Größe Null hat. In diesem Fall müßte man das Backup zurückkopieren.

      Fällt mir gerade ein, wo liegt den die Schmerzgrenze für die Größe einer zu lesenden Datei. Ich meine hier speziell, was passt in eine @Liste oder in einen $Scalar.

      In 16-Bit Pascal kann ich in ein Listenelement 16.000 Einträge mit einer max. Länge von 255 Zeichen ablegen. (war schon öfters ein Problem) In 32-Bit bin ich bisher noch auf keine Grenze gestoßen. Wie ist es bei Perl.

      Danke noch einmal
      Hansi

      1. Hi,

        die zweite Instanz liest leere Daten, während die erste gerade speichert, und speichert dieselben später ab. Die Daten gehen also verloren.
        Das ist ja katastrophal. Jetzt weiß ich wenigstens warum mir letzten eine Datei auf Null gesetzt wurde.

        exakt... :-)

        perldoc -f flock
        ich bin Linux-Neuling und total Windowsverseucht. Deshalb danke auch für diesen Tip. Hier jetzt allerdings ein Loblied auf Linux zu singen, würde wohl den Rahmen sprengen.

        Ich benutze auch Windows, aber zumindest kann ich auf einer Linux-Oberfläche "überleben". Soweit sollte man es schon beherrschen, also: üben, üben, üben! ;-)

        Ich habe die Sache übrigens sehr umständlich gelöst (weil ich flock selber nicht richtig verstehe *g*)[...]
        Da bin ich aber beruhigt, daß auch ein Profi!? seine Schwächen eingesteht.

        *g* :-)

        Die Idee ist famous. ich habe deshalb eine kleine Funktion erstellt, die genau das macht.

        Nicht übel, wirklich. Mit dem -e Switch (vergl. perldoc -f -X) kann man es noch verbessern ("-e $file" prüft, ob eine Datei existiert):

        sub waittofileclose
          {
          $f = $_;
          $isopen = "$filename.isopen";
          $testagain = 0;

        while (-e $isopen && ++$testagain < 20) { select(undef,undef,undef,0.1); }

        Die Datei brauchst Du übrigens erst vor dem Schreibzugriff zu erstellen. Nebenbei hoffe ich, daß die Verwendung von $f und $filename gewollt ist? ;-)

        Vielleicht kann man ja noch alle 10 oder 100 Aufrufe ein Backup der Datendatei anlegen. Natürlich nur, wenn die Datendatei nicht die Größe Null hat. In diesem Fall müßte man das Backup zurückkopieren.

        Auch nicht schlecht. Die Größe eines Files bekommt man mit -s $file ;-)

        Fällt mir gerade ein, wo liegt den die Schmerzgrenze für die Größe einer zu lesenden Datei. Ich meine hier speziell, was passt in eine @Liste oder in einen $Scalar.

        Kommt darauf an. Wie groß sind Arbeitsspeicher und Swapdatei? ;-)
        Prinzipiell gibt es dazu keine Begrenzung.

        Cheatah

        1. Hallo,

          Ich benutze auch Windows, aber zumindest kann ich auf einer Linux-Oberfläche "überleben". Soweit sollte man es schon beherrschen, also: üben, üben, üben! ;-)

          Naja, ich habe zumindest einen Fileserver und einen Webserver zum Testen einrichten können. Den Fileserver hatte ich zuvor unter WinNT eingerichtet und das Miststück ist mir im Schnitt zweimal die Woche abgestürzt. Den Webserver verwende ich nur für den Test meiner Skripte und meiner Homepage's. Auf dem habe ich 3 Virtuelle Host's jeweils mit einer eigenen IP. War aber recht heftig sich dabei von Windows zu lösen und sich auf Windows einzustellen.

          Nicht übel, wirklich. Mit dem -e Switch (vergl. perldoc -f -X) kann man es noch verbessern ("-e $file" prüft, ob eine Datei existiert):

          sub waittofileclose
            {
            $f = $_;
            $isopen = "$filename.isopen";
            $testagain = 0;

          while (-e $isopen && ++$testagain < 20) { select(undef,undef,undef,0.1); }

          Ich wußte doch, daß es auch noch besser geht. Danke.

          Die Datei brauchst Du übrigens erst vor dem Schreibzugriff zu erstellen. Nebenbei hoffe ich, daß die Verwendung von $f und $filename gewollt ist? ;-)

          Das stammt noch aus dem Testskript. Stimmt ist so natürlich nicht richtig und brigt eine Menge Gefahren. Der Parameter $f wurde beim ersten Anlauf nicht richtig übernommen. Deshalb habe ich weiter oben die Variable $filename zweckentfremdet und Sie kurz hier mitverwendet. Da habe ich überigens öfters Schwierigkeiten. In Pascal gibt es andere Richtlinen für Variabeln und Parameter und es funktioniert nur eine Vorwärtsdeklaration. D.h. Die Variable muß definiert sein, und das auch vor dem Verwenden. In Perl kann ich irgendwo eine Variable verwenden und automatisch ist sie für das ganze Skript sichtbar. Das ist natürlich nicht schlecht. Man muß sich halt darauf einstellen.

          Vielleicht kann man ja noch alle 10 oder 100 Aufrufe ein Backup der Datendatei anlegen. Natürlich nur, wenn die Datendatei nicht die Größe Null hat. In diesem Fall müßte man das Backup zurückkopieren.

          Auch nicht schlecht. Die Größe eines Files bekommt man mit -s $file ;-)

          Kommt darauf an. Wie groß sind Arbeitsspeicher und Swapdatei? ;-)

          Also auf meinem Server 24MB und 120 MB. Habe ich willkürlich gewählt.

          Prinzipiell gibt es dazu keine Begrenzung.

          Und wie es der Teufel will, habe ich gestern noch in iregendeiner Dok eine kurze Erläuterung dazu gefunden. Es gbt demnach keinerlei Beschränkungen.

          Gruß Hansi

      2. Hallo,

        auch hier möchte ich Dir erst einmal danken. Ich habe auch diese Geschichte mal ausprobiert. Und möchte auch hier das Resultat kurz darstellen.

        die zweite Instanz liest leere Daten, während die erste gerade speichert, und speichert dieselben später ab. Die Daten gehen also verloren.
        Das ist ja katastrophal. Jetzt weiß ich wenigstens warum mir letzten eine Datei auf Null gesetzt wurde.

        Du meinst vermutlich flock? Die Beschreibung dazu findest Du bei der bei Perl mitgelieferten Doku. Unter Windows in der HTML-Doku perlfunc, unter Unix schneller mit
        stimmt natürlich.

        perldoc -f flock
        ich bin Linux-Neuling und total Windowsverseucht. Deshalb danke auch für diesen Tip. Hier jetzt allerdings ein Loblied auf Linux zu singen, würde wohl den Rahmen sprengen.

        Ich habe die Sache übrigens sehr umständlich gelöst (weil ich flock selber nicht richtig verstehe *g*)[...]
        Da bin ich aber beruhigt, daß auch ein Profi!? seine Schwächen eingesteht.

        [...], indem ich vor jedem Schreibzugriff eine Dummy-Datei anlege, die sozusagen als Markierung dient. Vor jedem Lesezugriff prüfe ich in einer while-Schleife, ob diese Datei existiert. Vorsicht, es kann zu einer Endlosschleife führen, deshalb prüfe nur z.B. 10 mal und warte dazwischen mit select(undef,undef,undef,0.1) eine Zehntelsekunde (z.B.).
        Die Idee ist famous. ich habe deshalb eine kleine Funktion erstellt, die genau das macht.

        sub waittofileclose
          {
          $f = $_;
          $isopen = "$filename.isopen";
          $testagain = 0;
          while ($testagain < 20)
            {
            if (open (TESTFILE, "$isopen"))
              {
              close (TESTFILE);
              select(undef,undef,undef,0.1);
              $testagain++;
              }
            else
              {
              $testagain = 20;
              open (TESTFILE, ">$isopen");
              close (TESTFILE);
              }
            }
          }

        Diese Funktion rufe ich vor dem eigentliche öffenen der eigentlichen zu bearbeitenden Datei auf. Wenn ich dann alle Aktionen an der Hauptdatei durchgeführt habe, lösche ich die Kontrolldatei mit dem Befehl unlink $isopen;
        Sollte nun ein anderer Prozess in einer Warteschleife stecken, merkt dieser ja, daß die Datei entfernt wurde und kann nun seine Arbeiten durchführen. usw.

        Vielleicht kann man ja noch alle 10 oder 100 Aufrufe ein Backup der Datendatei anlegen. Natürlich nur, wenn die Datendatei nicht die Größe Null hat. In diesem Fall müßte man das Backup zurückkopieren.

        möchte meinen, daß dies die Serverleistung unnötig in Anspruch nimmt.
        Vorschlag:

        Konstanten fuer flock()

        $LOCK_SH = 1;
        $LOCK_EX = 2;
        $LOCK_NB = 4;
        $LOCK_UN = 8;

        ##########

        open (DATEI, ">>datei.ext") or die ("$!: can‚t open datei.ext\n");
        flock (DATEI, $LOCK_EX) or die ("$!: can‚t get lock\n");
        print (DATEI "$string\n");

        flock (DATEI, $LOCK_UN);
        close (DATEI);

        habe so bis jetzt noch keine bösen Überraschungen erlebt. :-)

        Gruß Steffen

        1. Hi,

          möchte meinen, daß dies die Serverleistung unnötig in Anspruch nimmt.
          Vorschlag:

          Konstanten fuer flock()

          sollten vordefiniert sein ;-)

          open (DATEI, ">>datei.ext") or die ("$!: can‚t open datei.ext\n");
          flock (DATEI, $LOCK_EX) or die ("$!: can‚t get lock\n");
          print (DATEI "$string\n");

          flock (DATEI, $LOCK_UN);
          close (DATEI);

          habe so bis jetzt noch keine bösen Überraschungen erlebt. :-)

          Ich schon - damit werden nämlich nur Schreib- und keine Lesezugriffe gesperrt. Wenn eine Instanz die Datei gerade schreibt, kann eine andere Instanz dieselbe Datei immer noch lesen. Leider ist die Datei in dem Moment leer. Wenn dann Schreibzugriffe wieder erlaubt werden, wird die leere Datei ggf. wieder gespeichert - trotz flock. Hat mich einige Datenverluste gekostet, bis ich dann auf die genannte Variante umgestiegen bin.

          Cheatah

          1. Hi there

            open (DATEI, ">>datei.ext") or die ("$!: can‚t open datei.ext\n");
            flock (DATEI, $LOCK_EX) or die ("$!: can‚t get lock\n");
            print (DATEI "$string\n");

            flock (DATEI, $LOCK_UN);
            close (DATEI);

            habe so bis jetzt noch keine bösen Überraschungen erlebt. :-)

            Ich schon - damit werden nämlich nur Schreib- und keine Lesezugriffe gesperrt. Wenn eine Instanz die Datei gerade schreibt, kann eine andere Instanz dieselbe Datei immer noch lesen. Leider ist die Datei in dem Moment leer. Wenn dann Schreibzugriffe wieder erlaubt werden, wird die leere Datei ggf. wieder gespeichert - trotz flock. Hat mich einige Datenverluste gekostet, bis ich dann auf die genannte Variante umgestiegen bin.

            Nach Theorie sollte nach einer Sperre das Betriebssystem den anderen Prozess solange anhalten bis der erste Prozess die Datei wieder freigibt. Man muss also auch bei nur lesenden Zugriffen ein File-Locking durchfuehren ($LOCK_SH = 1)!!
            Man kann uebrigens auch testen, ob ein Lock gesetzt ist ($LOCK_NB = 4).
              flock(FH, $LOCK_EX $LOCK_NB) or print "locked\n";

            Gruss,
            Beat

            [Quelle: c't 4/99]

        2. Hallo,

          möchte meinen, daß dies die Serverleistung unnötig in Anspruch nimmt.

          Auf jeden Fall Danke.

          Vorschlag:

          Konstanten fuer flock()

          $LOCK_SH = 1;
          $LOCK_EX = 2;
          $LOCK_NB = 4;
          $LOCK_UN = 8;

          ##########

          open (DATEI, ">>datei.ext") or die ("$!: can‚t open datei.ext\n");
          flock (DATEI, $LOCK_EX) or die ("$!: can‚t get lock\n");
          print (DATEI "$string\n");

          flock (DATEI, $LOCK_UN);
          close (DATEI);

          Also wie schon gesagt, ich kenne den Befehl flock nicht 100%ig. Wenn ich Deinen Vorschlag rictig interpretiere, stirbt das Skript, wenn es die Datei nicht in Beschlag nehmen kann. Folgedessen, sind damit auch die Daten verloren, die durch das Skript ermittelt wurden und in der Datei gespeichert werden sollen. Genau das ist es was ich vermeiden möchte. Es sollen so gut und so sicher wie alle Daten gespeichert werden.

          Das mit der Serverleistung sehe ich nicht so. Da im besten Fall, die Funktion nur 1 mal durchflogen wird. Wenn dieser, eher unwahrscheinliche, Fall eintritt, daß zwei oder mehr User gleichzeitig auf das Skript zugreifen, werden diese lediglich in eine Warteschleife gestellt. (zudem hat Cheatah in der vorangegangenen Mitteilung noch eine Verbesserung eingebracht, mit der man die Datei nicht mehr öffnen muß).

          habe so bis jetzt noch keine bösen Überraschungen erlebt. :-)

          Noch einmal Danke ür Deinen Hinweis. Ich habe so auf jeden Fall ein bißchen mehr dazugelernt. Ich bin mir auch sicher, daß ich Deine Info mit Sicherheit in einem meiner Skripts verwenden kann.

          Gruß Hansi

      3. [...], indem ich vor jedem Schreibzugriff eine Dummy-Datei anlege, die sozusagen als Markierung dient. Vor jedem Lesezugriff prüfe ich in einer while-Schleife, ob diese Datei existiert. Vorsicht, es kann zu einer Endlosschleife führen, deshalb prüfe nur z.B. 10 mal und warte dazwischen mit select(undef,undef,undef,0.1) eine Zehntelsekunde (z.B.).
        Die Idee ist famous. ich habe deshalb eine kleine Funktion erstellt, die genau das macht.

        Ich halte die Idee mit der Datei nicht für so "famos" (obwohl ich praktisch dasselbe hier in einem Produkt implementiert habe, weil ich ein Semaphor auf einer shell-Ebene haben wollte und das am schnellsten ging ;-).

        Wenn die Daten kostbar sind, dann ist eine Datei als Synchronisation nicht gut genug.
        Das Problem ist, daß es eine kritische Phase gibt, nämlich genau zwischen dem Prüfen der Sperr-Datei und dem Anlegen der Sperrdatei. Wenn das zwei Prozesse gleichzeitig versuchen, dann sind beide drin in der gefährlichen Zone.
        Der Trick muß darinbestehen, das Testen und das Setzen des Semaphors als unteilbare Operation durchzuführen. Auf alten Großrechnern gab es dafür bereits spezielle Maschinenbefehle "Test and Set", die genau so etwas mit einem Bit im Hauptspeicher tun konnten - selbst wenn durch einen Prozeßwechsel ein anderer Prozeß die CPU bekommt, kann er doch nicht diesen einen Befehl unterbrechen.

        So gesehen ist flock() eine wesentlich zuverlässigere Methode.
        Wenn Dir Deine Daten kostbar sind, dann solltest Du bei Synchronisation auf keinen Fall mit der zweitbesten Lösung zufrieden sein.

        1. Hallo,

          Ich halte die Idee mit der Datei nicht für so "famos" (obwohl ich praktisch dasselbe hier in einem Produkt implementiert habe, weil ich ein Semaphor auf einer shell-Ebene haben wollte und das am schnellsten ging ;-).

          Wenn die Daten kostbar sind, dann ist eine Datei als Synchronisation nicht gut genug.

          Das ist der Punkt die Daten sind sehr kostbar. Mit der besprochenen Lösung bin ich auf jeden Fall einen Schritt weiter.

          Das Problem ist, daß es eine kritische Phase gibt, nämlich genau zwischen dem Prüfen der Sperr-Datei und dem Anlegen der Sperrdatei. Wenn das zwei Prozesse gleichzeitig versuchen, dann sind beide drin in der gefährlichen Zone.

          Stimmt, auch das kann passieren. Habe ich auch schon in erwägung gezogen.

          Der Trick muß darinbestehen, das Testen und das Setzen des Semaphors als unteilbare Operation durchzuführen. Auf alten Großrechnern gab es dafür bereits spezielle Maschinenbefehle "Test and Set", die genau so etwas mit einem Bit im Hauptspeicher tun konnten - selbst wenn durch einen Prozeßwechsel ein anderer Prozeß die CPU bekommt, kann er doch nicht diesen einen Befehl unterbrechen.

          So gesehen ist flock() eine wesentlich zuverlässigere Methode.
          Wenn Dir Deine Daten kostbar sind, dann solltest Du bei Synchronisation auf keinen Fall mit der zweitbesten Lösung zufrieden sein.

          Durch die Diskussion in diesem Thread habe ich ja einiges zur Verwendung von flock() erfahren. Ich habe mir auch schon überlegt, ob es vielleicht eine Möglichkeit gibt (wenn überhaupt sinvoll) die Warteschleife und flock zu kombinieren. Es ist auch noch offen, ein Backup der Datei anlegen zu lassen. Diese Dinge zusammen müßten wohl ausreichen um die Daten so genau wie nur möglich aufzunehmen und zu speichern bzw. wieder zur Verfügung zu stellen.

          Wie das nun genau aussehen könnte, weiß ich noch nicht ganz. Vielleicht hat aber noch jemand eine Idee.

          Hansi

          1. Wenn die Daten kostbar sind, dann ist eine Datei als Synchronisation nicht gut genug.
            Das ist der Punkt die Daten sind sehr kostbar. Mit der besprochenen Lösung bin ich auf jeden Fall einen Schritt weiter.

            Dann solltest Du darüber nachdenken, eine Lösung zu verwenden, die dem Wert der Daten angemessen ist.
            Wenn die Daten wirklich "kostbar" sind, also DM XXXXX.- und mehr, würde ich einen Synchronisationsmechanismus verwenden, der kommerziellen Maßstäben genügt - also eine richtige relationale Datenbank (mein Vorschlag: Oracle auf SUN).
            Synchronisation quasi-gleichzeitiger Zugriffe ist ein Problem, mit dem sich Datenbankdesigner schon seit 2-3 Jahrzehnten befassen, und das mit ziemlichem Erfolg. Das Transaktionskonzept einer richtigen relationalen Datenbank ermöglich es dem Anwender, das Thema Synchronisation vollkommen auszuklammern - die Datenbank kümmert sich ganz alleine darum, daß die aktuelle Sicht auf die Daten Sinn macht, daß gegenseitiges Überschreiben keine Probleme auslöst etc.

            Durch die Diskussion in diesem Thread habe ich ja einiges zur Verwendung von flock() erfahren. Ich habe mir auch schon überlegt, ob es vielleicht eine Möglichkeit gibt (wenn überhaupt sinvoll) die Warteschleife und flock zu kombinieren. Es ist auch noch offen, ein Backup der Datei anlegen zu lassen. Diese Dinge zusammen müßten wohl ausreichen um die Daten so genau wie nur möglich aufzunehmen und zu speichern bzw. wieder zur Verfügung zu stellen.
            Wie das nun genau aussehen könnte, weiß ich noch nicht ganz. Vielleicht hat aber noch jemand eine Idee.

            Einen solchen Mechanismus brauchst Du in jedem Fall. Wenn Dein Prozeß versucht, das Semaphor zu setzen, und flock() ihm ein FALSE zurückmeldet, dann ist zu erwarten, daß der andere Prozeß noch eine Weile am Arbeiten ist. Und in der Zwischenzeit würdest Du mit weiteren flock()-Versuchen lediglich das System langsamer machen (busy wait).
            Also wäre eine Konstruktion der Art
                while (flock() == FALSE) {sleep (time)}
            empfehlenswert. Den idealen Wert für "time" zu finden, hängt davon ab, wieviel Du über die mittlere Verweildauer Deiner Prozesse weißt - Du willst ja weder zu oft abfragen noch zu lange bis zur nächsten Abfrage warten. Vielleicht ist der ideale Wert sogar nicht konstant, sondern dynamisch zu berechnen, etwa in Abhängigkeit von der bisherigen Wartezeit ...

            Generelles Problem: Während Prozeß 2 auf Prozeß 1 wartet, kann Prozeß 3 ebenfalls zu warten beginnen. Wer nach Prozeß 1 als nächster durchkommt, ist Zufall. Die angegebene triviale Schleife stellt nicht sicher, daß Prozeß 2 *jemals* durchkommt (oder gar vor Prozeß 2). Wenn Du die Abfragefrequenz bei längerer Wartezeit erhöhst, verbessserst Du lediglich die Chancen der "alten" Prozesse.
            Wenn Du das aber garantieren mußt, dann mußt Du etwas anderes verwenden (eine Warteschlange, beispielsweise über ein UNIX-socket).

            Das allgemeine Thema der Prozeßsynchronisation ist so vielfältig, daß man leicht ins Schwafeln kommt, so wie ich gerade ... :-)

            1. Hallo Michael,

              Wenn die Daten wirklich "kostbar" sind, also DM XXXXX.- und mehr, würde ich einen [...]

              So wertvoll nun auch wieder nicht.

              [...]Synchronisationsmechanismus verwenden, der kommerziellen Maßstäben genügt - also eine richtige relationale Datenbank (mein Vorschlag: Oracle auf SUN).

              Autsch, das ist eine Spur zu prof.

              Ich suche genau nach dem Kompromis, der die Syncronisation so gut wie möglich regelt und gleichzeitig aber vom Aufwand (Lernen, Entwicklung, Kosten) her vertretbar bleibt. Mit der Diskussion bin ich auf jeden Fall einige Schritte weiter gekommen.

              Das allgemeine Thema der Prozeßsynchronisation ist so vielfältig, daß man leicht ins Schwafeln kommt, so wie ich gerade ... :-)

              Dank Dir und den anderen Teilnehmer an diesem Thread habe ich so nun eine Menge neuer Impulse erhalten, mit denen ich mich nun mal auf die Suche nach noch mehr Info machen werde. Ich möchte auch Dir für Deine Ausführungen danken. Sobald ich zu einem Ergebnis gekommen bin, werde ich mich wieder melden.

              Gruß Hansi

          2. Hi Hansi!
            (Nimm's mir nicht uebel, Dein Name laesst sich zwar leicht schreiben, aber klingt der Qualitaet Deiner Beitraege nicht angemessen. ;-))

            Das Problem ist, daß es eine kritische Phase gibt, nämlich genau zwischen dem Prüfen der Sperr-Datei und dem Anlegen der Sperrdatei. Wenn das zwei Prozesse gleichzeitig versuchen, dann sind beide drin in der gefährlichen Zone.

            Stimmt, auch das kann passieren. Habe ich auch schon in erwägung gezogen.

            Vor inzwischen ziemlich langer Zeit hatte jemand vorgeschlagen, nicht auf die Existenz einer Sperrdatei abzufragen, sondern auf die Nicht-Existenz. Dann koennte man naemlich mit dem unlink()-Befehl die Datei vom OS loeschen lassen, und dieses tut das ganz bestimmt nur einmal, denn es nutzt intern ohne Zweifel entsprechende Synchronisierungsmechanismen. unlink() gibt die Zahl der geloeschten Dateien zurueck, man weiss also, ob das Loeschen erfolgreich war oder man auf einen anderen Prozess warten muss. Ist ein Prozess mit seiner Arbeit fertig, muss er die Datei wieder anlegen, um einen evtl. wartenden Prozess weiterlaufen zu lassen.

            Durch die Diskussion in diesem Thread habe ich ja einiges zur Verwendung von flock() erfahren.

            Probier einfach ein bisschen mit flock() herum. Zum Beispiel Datei sperren, 10 Sekunden warten, waehrenddessen Script ein zweites mal starten. Das ganze dokumentierst Du mit Statusmeldungen, damit Du weisst, wo der Programmablauf gerade steht. Dann wirst Du sehen, ob der zweite Prozess wartet oder nicht und unter welchen Umstaenden und unter welchen nicht.

            Ich habe mir auch schon überlegt, ob es vielleicht eine Möglichkeit gibt (wenn überhaupt sinvoll) die Warteschleife und flock zu kombinieren.

            Halte ich durchaus fuer sinnvoll. Nehmen wir z.B. das Script fuer ein Forum wie dieses: Wuerdest Du den zweiten Prozess einfach abbrechen, wenn er die Kontrolle ueber eine bestimmte Datei nicht auf Anhieb bekommt, wuerde das den Verlust des Postings bedeuten, durch welches der zweite Prozess gestartet wurde. Also ruhig in einer Schleife ein paar mal probieren (ich verwende z.B. oft 10 Versuche mit je einer Sekunde Pause). Michael hat dazu ein paar interessante Kommentare geschrieben (daran hatte ich noch gar nicht gedacht).

            Calocybe

            1. Hallo Calocybe,

              (Nimm's mir nicht uebel, Dein Name laesst sich zwar leicht schreiben, aber klingt der Qualitaet Deiner Beitraege nicht angemessen. ;-))

              Na ich hoffe das war ein Kompliment *ggg*. Wenn du eine Idee für mich hast, laß es mich bitte wissen.

              Probier einfach ein bisschen mit flock() herum. [...]

              Oh, das klingt nach Arbeit *g*

              Bevor dieser Thread nun rausgeschoben wird, möchte ich mich auf jeden Fall noch für Deinen Beitrag bedanken. Sobald ich zu einer Lösung gekommen bin werde ich mich bestimmt wieder melden.

              Gruß Hansi

              1. Hi Hansi!

                Na ich hoffe das war ein Kompliment *ggg*.

                Kannst Du ruhig so nehmen, ja. :-)

                Wenn du eine Idee für mich hast, laß es mich bitte wissen.

                Was, fuer ein Pseudonym? Du meinst, ein aehnlich schwer zu buchstabierendes wie meines? Naja, dieses hatte mich seinerzeit schon genug Muehe gekostet. ;-)

                Probier einfach ein bisschen mit flock() herum. [...]
                Oh, das klingt nach Arbeit *g*

                Komisch, den Gedanken hatte ich auch. ;-)

                Bevor dieser Thread nun rausgeschoben wird, möchte ich mich auf jeden Fall noch für Deinen Beitrag bedanken. Sobald ich zu einer Lösung gekommen bin werde ich mich bestimmt wieder melden.

                Ja, tu das. Wir hatten das Thema zwar schon ab und zu mal, aber soviel ich weiss hatten wir es nie bis zur letzten Konsequenz ausdiskutiert (sonst haetten wir Dir ja auch einfach einen Link praesentieren koennen). Auf jeden Fall halte ich die Loesung mit Sperr-Dateien fuer sehr unelegant. Es gibt in Perl auch Semaphore-Funktionen (semctl, semget, semop). Ich hab mit schon die Manpages fuer die entsprechenden C-Funktionen geholt (letztlich werden einfach die C-Funktionen vom Perl-Interpreter aufgerufen). Ich muss sie mir endlich mal durchlesen, vielleicht kann man damit auch was anfangen. Ich befuerchte jedoch, dass diese Funktionen gar nicht auf die Windows-Versionen von Perl umgesetzt sind.

                Viel Spass, Calocybe

                1. Hallo, Calocybe

                  Kannst Du ruhig so nehmen, ja. :-)

                  Dann bin ich beruhigt.

                  Was, fuer ein Pseudonym?

                  So dachte ich :-)

                  Du meinst, ein aehnlich schwer zu buchstabierendes wie meines? Naja, dieses hatte mich seinerzeit schon genug Muehe gekostet. ;-)

                  Es hat sich aber gelohnt *g*

                  [...]Auf jeden Fall halte ich die Loesung mit Sperr-Dateien fuer sehr unelegant. [...]

                  Die Lösung ist wahrhaftig etwas ungewöhnlich. Also in Windows wäre ich nie auf sowas gekommen. Trotzdem finde ich diesen Gedanken nicht schlecht. Es kommt wahrscheinlich nur darauf an, wie man die Dinger benutzt.

                  [...]Es gibt in Perl auch Semaphore-Funktionen (semctl, semget, semop). Ich hab mit schon die Manpages fuer die entsprechenden C-Funktionen geholt (letztlich werden einfach die C-Funktionen vom Perl-Interpreter aufgerufen). Ich muss sie mir endlich mal durchlesen, vielleicht kann man damit auch was anfangen. Ich befuerchte jedoch, dass diese Funktionen gar nicht auf die Windows-Versionen von Perl umgesetzt sind.

                  Gott sei Dank muß es nur unter Linux laufen. Dennoch bin ich mir nicht ganz sicher, diese Funktionen schon einmal in einem C-compiler unter Windows gesehen zu haben (kann mich natürlich auch täuschen)

                  Viel Spass, Calocybe

                  Wenn es Neu, Schwierig und unlösbar scheint, macht es meißtens am meißten Spass :-()

                  Bis dann Hansi