Rolf Rost: Atomares Lock

Hallo Forumsgemeinde,

ausnahmsweise muss ich mich mal wieder selbst darum kümmern, dass ein atomares (nicht mehr teilbares) Locking tut (in PERL).

Praktisch soll es so sein, dass jeder Prozess, der einen Record schreibt, ein Lock setzt und diesen Lock am Ende auch wieder aufhebt. Wenn ein Lock gesetzt ist (hier in einem hash, der mit DB_File gebunden, einem jeden Prozess zur Verfügung steht), soll der Prozess in eine Warteschleife gehen und erst dann weitermachen, wenn der andere Prozess den Lock aufgehoben hat.

Problematisch sind deadlocks, also Locks die hängengeblieben sind, falls mal ein Prozess vorzeitig abgebrochen wurde und nicht mehr dazukam, einen Lock aufzuheben.

Ich denke, das könnte so gehen, dass ich, im Falle eines Locks den Prozess in eine Queue schicke und max. 1 Mio mal schaue ob der Lock noch steht. Ist der Lock vorher wech - ok. Ansonsten wird nach 1 Mio Versuchen der Lock neu gesetzt.

Was meint den Ihr - Hat jemand Erfahrung mit solchen Dingen, insbesondere mit den zu erwartenden Prozesszeiten | Versuchen in der Queue - hinsichtlich eines deadlocks?

Viele Grüße, Rolf

lock - unlock

sub trylock{
 my $att;
 while( $lockdb{'lock'} ){ # gehen in die Warteschleife wenn ein lock gesetzt ist...
  $att++;
  last if $att == 1_000_000; # An dieser Stelle steht fest, dass es ein deadlock ist vom Vorgänger
 }
 $lockdb{'lock'} = 1; # selbst ein lock setzen, egal ob vorher die Schleife durchlaufen wurde
 return;
}

  1. Hello,

    Hurra, er lebt noch!

    Es ist sinnlos, locks nur atomar zu setzen.
    Man muss für sein Vorgangssystem eine Strategir entwickeln, die Dead-Locks verhindert.

    Außerdem ist eine Schleife, die auf ein Lock wartet, nur dann sinnvoll, wenn sie eine Verzögerungszeit bis zum nächsten Lock berücksichtigt und eine Abbruchbedingung für die Anzahl der Retrys enthält sowie einen qualifizierten Fehlercode produziert. Sonst ergibt das solch einen Unsinn, wie die flock()-Funktion von PHP, wenn man nicht dediziert LOCK_NB setzt. Das script wartet ggf. bis zum Script-Timeout auf das Lock. Das ist weder benutzerfreundlich, noch förderlich für die Performance.

    Harzliche Grüße aus http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau
    1. hallo Tom,

      Es ist sinnlos, locks nur atomar zu setzen.

      Warum? Ich halte das keineswegs für sinnlos.

      Man muss für sein Vorgangssystem eine Strategie entwickeln, die Dead-Locks verhindert.

      Das mag schon, so pauschal gesagt, richtig sein. Aber man stößt beim Programmieren immer wieder auf irgendwelche Detailfragen, und _hier_ hat Rolf meines Erachtens eine ganz interessante Detailfrage erwischt.

      Außerdem ist eine Schleife, die auf ein Lock wartet, nur dann sinnvoll, wenn sie eine Verzögerungszeit bis zum nächsten Lock berücksichtigt und eine Abbruchbedingung für die Anzahl der Retrys enthält sowie einen qualifizierten Fehlercode produziert.

      Genau das hat Rolf bereits in seinem Beispielcode vorgegeben (falls ich das denn jetzt richtig gelesen habe).

      Sonst ergibt das solch einen Unsinn, wie die flock()-Funktion von PHP, wenn man nicht dediziert LOCK_NB setzt. Das script wartet ggf. bis zum Script-Timeout auf das Lock.

      Ich fürchte, du bist "PHP-befangen". Hier gehts aber um Perl.

      Das ist weder benutzerfreundlich, noch förderlich für die Performance.

      Richtig, spielt aber für die Fragestellung erstmal eine völlig untergeordnete Rolle.

      Grüße aus Berlin

      Christoph S.

      1. hi Christoph,

        Es ist sinnlos, locks nur atomar zu setzen.

        Warum? Ich halte das keineswegs für sinnlos.

        Jo, das macht schon einen Sinn: Atomar heißt: Nicht teilbar.

        Es gibt im CGI Bereich oft genug Prozesse, die zur gleichen Zeit ablaufen und versuchen, zur gleichen Zeit an der gleichen Datei oder an der gleichen Tabelle zu schreiben.

        Derartiges wird unter dem Begriff Race Conditions gehandled...

        [..]

        Auf jeden Fall sollte es NICHT passieren, dass der Benutzer am Frontend (Browser) davon was mitbekommt oder eine Fehlermeldung sieht. Tatsächlich hat er ja auch keinen Fehler gemacht (obwohl nur Sch.. eingegeben).

        Im Bereich der kommerziellen Datenbanken gibt es das Transaktionskonzept, was so was verhindert. Wer transaktionssichere DBs einsetzen kann ist ja auch fein raus.

        Hat aber nicht jeder und immer zur Verfügung. Deswegen mein Post ...

        Viele Grüße, Rolf

    2. Hello,

      Hurra, er lebt noch!

      Danke Tom ;-)

      Oft genug sehe ich mich in der Rolle des 'Mieters' (Roman Polansky) und ständig aus dem Fenster stürzen, dann die Treppe wieder hochlaufen und wieder aus dem Fenster stürzen, ...

      Man muss für sein Vorgangssystem eine Strategir entwickeln, die Dead-Locks verhindert.

      Nun, wenn jeder Prozess sauber durchlaufen würde, gäbe es ja auch keine deadlocks. Aber lass mal einen abstürzen - zack! Schon haben wir einen deadlock.

      Außerdem ist eine Schleife, die auf ein Lock wartet, nur dann sinnvoll, wenn sie eine Verzögerungszeit bis zum nächsten Lock berücksichtigt und eine Abbruchbedingung für die Anzahl der Retrys enthält sowie einen qualifizierten Fehlercode produziert. Sonst

      Jo, die Kalkulation der Verzögerungszeiten in Verbindung mit der Abbruchbedingung, das war ja meine eigentliche Frage ;-)

      Nomalerweise laft ein Prozess so um die 10.. 100 ms um einen Datensatz in eine Tabelle zu schreiben. Solange ein Lock. Aber: Es wäre doch unklug, das Erkennen eines deadlocks an der Zeit festzumachen. Ergo, dachte ich mir, lass eine Schleife losrennen und mach 1 Mio Versuche - da bist du unabhängig vom Blech.

      Schnelles Blech: 10ms Prozess, 1 Mio attempts in 15ms - sind genug zu erkennen, dass der Lock hängt...

      Langsames Blech: 100ms Prozess, 1 Mio attempts in 150ms - sind genug zu erkennen, dass der Lock hängt...

      Was meinst Du denn dazu?

      LG; Rolf