Cruz: flock() Lösung

Hi!

Tut mir Leid, daß ich schon wieder mit diesem Thema anfange, aber im Archiv stehen nur jede Menge Diskussionen und keine richtige Lösung. Darum Poste ich hier mal eine erste Version für eine flock Lösung und ich hoffe, daß am Ende dieses Threads eine Lösung im Quellcodeformat steht, die noch unsere Enkel aus dem Archiv suchen werden.

Also hier we go:

----------------------------------------------------------------------------------------------------------------------------------

#!/usr/bin/perl

$timeout=10000; #how long the script waits between attempts to get a lock
$exit=100;          #how many attempts to get a lock before exiting the script

if file is locked keep trying until $exit

if (!flock(FILE,2))
{
until ($released eq TRUE or $x>$exit) {

# little timeout  
$i=0;  
for ($i=0;$i<$timeout;$i++) {}  

#count attempts
              $x++;

if (flock(FILE,2)) {$released=TRUE;}  

} # end until  

} # end if

if too many attempts

if ($exit>100) {
print "Server too busy, please try again.";
die;
}

else {

lock file

flock(FILE,2); # (I don't know if file still needs to be locked after "if (flock(FILE,2))")

do your sutff { }

release file

flock(FILE,8);

} # end else

---------------------------------------------------------------------------------------------------------------------------------

Ich weiß z.B. schon mal nicht genau, ob der flock noch gesetzt werden muss, nachdem man in einer if  clause schon versucht hat den lock zu kriegen.

Gruß
Cruz

  1. $timeout=10000; #how long the script waits between attempts to get a lock
    $exit=100;          #how many attempts to get a lock before exiting the script

    if file is locked keep trying until $exit

    if (!flock(FILE,2))
    {

    Was soll das denn? "flock FILE,2" wartet solange, bis der andere Prozess / die anderen Prozesse das File wieder freigeben haben. Wenn Du nur pruefen willst, ob eine Datei gelockt ist, musst Du LOCK_SH/LOCK_EX _und_ LOCK_NB benutzen.

    release file

    flock(FILE,8);

    Das lass lieber bleiben. Schliesse die Datei einfach mit close, das impliziert einen LOCK_UN und ist wesentlich sicherer.

    Peter

    1. "flock FILE,2" wartet solange, bis der andere Prozess / die anderen Prozesse das File wieder freigeben haben.

      Auch auf UNIX?

      1. Auch auf UNIX?

        Da auf jeden Fall.

        Peter

        1. Ergo, die optimal flock() Lösung ist so?

          open (FILE, "file.ext");
          flock(FILE,2);

          #do your stuff

          close(FILE);

          1. Ergo, die optimal flock() Lösung ist so?
            open (FILE, "file.ext");
            flock(FILE,2);
            #do your stuff
            close(FILE);

            Nein, für den reinen Lesezugriff ist LOCK_SH sinnvoller. Also:

            flock FILE, 1;

            Peter

            1. Nein, für den reinen Lesezugriff ist LOCK_SH sinnvoller. Also:
                flock FILE, 1;

              Ja ne soll schon Schreibzugriff sein. Was bewirkt denn überhaupt der shared lock genau? Wenn andere Prozesse auch die Datei lesen können, warum soll sie dann überhaupt "gelockt" sein?

              Übrigens, Danke für die Geduld und die ganzen Tipps.

              Cruz

              1. Ja ne soll schon Schreibzugriff sein. Was bewirkt denn überhaupt der shared lock genau? Wenn andere Prozesse auch die Datei lesen können, warum soll sie dann überhaupt "gelockt" sein?

                Vielleicht gegen weitere Schreibzugriffe?

                Wenn Du in einer record-strukturierten Datei nur den Inhalt einer Zeile ändern willst, dann darf niemand sonst diese Zeile gleichzeitig schreiben können - aber andere Prozesse sollten (auf eigenes Risiko, daß sich die von ihnen gelesene Zeile gerade ändert) durchaus lesen dürfen, ohne Dich zu stören.

          2. Ergo, die optimal flock() Lösung ist so?

            open (FILE, "file.ext");
            flock(FILE,2);
            #do your stuff
            close(FILE);

            Das kommt darauf an, was Du unter "optimal" verstehst.
            Dein eigener Ansatz hatte ja immerhin ein Timeout-Konzept, was für eine CGI-Anwendung keine schlechte Idee ist (sonst gibt es einen Timeout durch den Webserver, und alles zerfällt zu feinstem Staub). flock() in der obigen Form ist abhängig von seiner Umwelt - und wenn diese das Semaphor ewig blockiert, dann hängst Du eben fest.

            Deshalb fände ich ja eine "Test and Set"-Operation besser - die würde genau das tun, was Du willst, und das Wartezeitverhalten könntest Du selbst regeln.

            1. Also dann vielleicht am besten so:

              ----------------------------------------------------------------------------------------------------------------------------------------

              #!/usr/bin/perl

              $timeout=10000; #how long the script waits between attempts to get a lock
              $exit=100;          #how many attempts to get a lock before exiting the script

              open (FILE, "file");

              if file is locked keep trying until $exit

              if (!flock(FILE,2))
              {
              until ($released eq TRUE or $x>$exit) {

              little timeout

              $i=0;
              for ($i=0;$i<$timeout;$i++) {}

              #count attempts
              $x++;

              if (flock(FILE,2)) {$released=TRUE;}

              } # end until

              } # end if

              if too many attempts

              if ($exit>100) {
              print "Server too busy, please try again.";
              close(FILE);
              die;
              }

              else {

              lock file

              flock(FILE,2);

              do your sutff { }

              close(FILE);

              } # end else

              ----------------------------------------------------------------------------------------------------------------------------------------

              Gruß
              Cruz

      2. Auch auf UNIX?

        Da auf jeden Fall.

        Peter

  2. Hi Cruz!

    Ich habe mal vor langer Zeit (naja, relativ) folgenden Code verwendet:

    $cFLOCK_SHARED = 1;
    $cFLOCK_EXCLUSIVE = 2;
    $cFLOCK_NOBLOCK = 4;
    $cFLOCK_UNLOCK = 8;

    $cTIMEOUT = 10;
    $cCOUNTERBASE = "local_counter.dat";

    if (! -e $cCOUNTERBASE) {
        open(CBASE, ">$cCOUNTERBASE");
        close(CBASE);
    }

    for ($i=0; (!open(CBASE, "+<$cCOUNTERBASE") && ($i < $cTIMEOUT)); $i++) { sleep(1) }
    abort() unless ($i < $cTIMEOUT);

    for ($i=0; (!flock(CBASE, $cFLOCK_EXCLUSIVE$cFLOCK_NOBLOCK) && ($i < $cTIMEOUT)); $i++) { sleep(1) }
    abort() unless ($i < $cTIMEOUT);

    do your stuff

    flock(CBASE, $cFLOCK_UNLOCK);
    close(CBASE);

    abort() ist eine eigene Funktion, die letztlich nur ein exit() oder die() macht. Hat bisher eigentlich noch nie Probleme gemacht, war aber auch noch nicht so sehr stark frequentiert, der Server auf dem das laeuft. Comments sind natuerlich erwuenscht.

    Calocybe