Server-Client mit Shared Memory -> Wie Beenden des Servers erkennen?

  • Hallo,


    Ich habe eine Server-Client Struktur mit Shared Memory implementiert.
    Der Zugriff ist über POSIX named Semaphoren geregelt.
    Es ist ein Art Banking-System, daher die Clients können dem Server anfragen "schicken", die er dann bearbeitet
    und beantwortet.


    Mein Problem ist jetzt, dass, wenn der Server beendet und der Client noch versucht eine Anfrage zu stellen,
    ein sem_wait im Client blockiert, allerdings ist der Semaphor ja zu der Zeit vom Server bereits gelöscht. (Auch laut /dev/shm/)
    Um den Client zu beenden, muss ich mit SIGINT die ganzen sem_waits abbrechen.


    Sollte das sem_wait bei nicht vorhandenem Semaphor nicht abbrechen und einen Fehler zurückgeben?
    Wird schwer gehen, da der Prozess ja geblocked ist, allerdings existiert dann ja kein Server mehr, der den Prozess wieder aufweckt.
    Wie könnte ich das Problem lösen?
    Sofern nichts anderes übrig bleibt, sollte ich dann jedes Mal bei einer Anfrage auf Existenz der Shared Memory abfragen?
    Wenn ja, wie kann man die Shared Memory überprüfen?


    MFG
    SuperMX

  • Hallo



    Mein Problem ist jetzt, dass, wenn der Server beendet und der Client noch versucht eine Anfrage zu stellen,
    ein sem_wait im Client blockiert, allerdings ist der Semaphor ja zu der Zeit vom Server bereits gelöscht. (Auch laut /dev/shm/)


    Ich nehme mal an, du meinst mit gelöscht du hast den Semaphor geunlinket. Dann ist er natürlich nicht mehr im Dateisystem sichtbar, aber gelöscht, im Sinne nicht mehr existent, ist er deshalb noch nicht unbedingt. Alle Prozesse die den Semaphor noch offen haben, können noch damit arbeiten, solange sie ihn nicht schließen. Erst wenn der letzte Prozess den Semaphor schließt wird er wirklich zerstört. Das gilt auch für den Shared Memory oder Files (File Deskriptoren) im allgemeinen: Es hört erst auf zu existieren, wenn es kein Prozess mehr geöffnet hat.


    sem_wait macht also auch weiter wie bisher, da der Semaphor ja noch immer existiert.


    Mit dem unlinken der Resourcen kannst du also nur verhindern, dass sich neue Clients verbinden. Für die bereits bestehenden musst du eine Möglichkeit finden, sie von der Beendigung des Servers zu benachrichtigen, bevor dieser die Resources für sich schließt.




    Sofern nichts anderes übrig bleibt, sollte ich dann jedes Mal bei einer Anfrage auf Existenz der Shared Memory abfragen?


    Würde ich nicht tun, es könnte ja schon ein neuer Server gestartet haben, der neue Resourcen erstellt hat. Du kannst die Überprüfung, ob der Server noch läuft, leicht in das Kommunikationsprotokoll einbauen.


    Ich hoffe für dich ist das jetzt ein wenig klarer.


    mfg,
    VaarSuvius

    [SS15, WS15, SS16, WS16: OSUE-Tutor; WS15, WS16: ASE-Tutor; SS16: SEPM-Tutor]

  • Hallo!


    Gut zu wissen, dass der Semaphor für die ehemals verbundenen Clients noch existiert. Nur zum Verständnis: Wird also die Shared Memory beim Unmappen für die bestehenden Clients auch nicht "gelöscht"?


    Damit hätte ich zwei Möglichkeiten:
    Falls das Shared Memory auch noch zugänglich ist, könnte ich vor dem Beenden des Servers einfach ein Flag setzen, um die Inaktivität des Servers anzuzeigen.


    Sollte das Shared Memory nicht mehr zugänglich sein, würde das heissen, dass der Server zwangsläufig vor dem Beenden alle Clients benachrichtigen muss.


    MFG,
    SuperMX

  • Hallo!
    Gut zu wissen, dass der Semaphor für die ehemals verbundenen Clients noch existiert. Nur zum Verständnis: Wird also die Shared Memory beim Unmappen für die bestehenden Clients auch nicht "gelöscht"?


    Ja, die anderen Prozesse können nach wie vor mit dem Shared Memory arbeiten.



    Falls das Shared Memory auch noch zugänglich ist, könnte ich vor dem Beenden des Servers einfach ein Flag setzen, um die Inaktivität des Servers anzuzeigen.


    Ja, das ist eine Möglichkeit.


    mfg,
    VaarSuvius

    [SS15, WS15, SS16, WS16: OSUE-Tutor; WS15, WS16: ASE-Tutor; SS16: SEPM-Tutor]

    Edited once, last by VaarSuvius ().

  • Hallo!


    Beim Client funktioniert das Erkennen, dass der Server beendet ist, jetzt mit der Flag sehr gut.
    Allerdings habe ich jetzt ein Problem beim Server bezüglich der Mutual Exclusion.


    Der Server sieht bei mir ca. so aus:



    Wenn der Server beenden möchte soll also nun das Flag gesetzt werden.
    Meine erste Vermutung war, einfach nach der Schleife Folgendes hinzuzufügen:

    Code
    1. sem_wait(s1);
    2. shared_memory_flag_false_setzen();
    3. sem_post(s2);


    Das Problem ist hierbei jedoch, dass man wieder zweimal SIGTERM für ein Beenden senden muss,
    da ja das zweite sem_wait wieder blockiert.
    Weggeben kann ich die Semaphorklammer unten jedoch nicht, da der Zugriff auf die Shared Memory
    ja mit den Clients synchronisiert werden muss.



    Also muss das Setzen der Flag noch irgendwie in der while-Schleife passieren.

    Code
    1. while(!want_quit) {
    2. sem_wait(s1);
    3. server();
    4. if(want_quit) {
    5. shared_memory_flag_false_setzen();
    6. }
    7. sem_post(s2);
    8. }


    sem_post ist atomic, aber das Problem ist hierbei, dass ein Signal nach dem if
    unterbrechen kann, sodass nicht sichergestellt ist, dass das Flag gesetzt wird.



    Der letzte Versuch von mir war, das Setzen mit einem zweiten Flag sicherzustellen:


    Aber hier lässt sich das Programm gar nicht mehr beenden. (Egal wie viele SIGTERMs)


    Wo könnte hier mein Denkfehler liegen? Ich glaube die Lösung ist essentiell um
    Semaphoren wirklich zu verstehen.
    Vielen Dank schonmal!


    MFG
    SuperMX


  • Weggeben kann ich die Semaphorklammer unten jedoch nicht, da der Zugriff auf die Shared Memory
    ja mit den Clients synchronisiert werden muss.



    Ich glaube die Lösung ist essentiell um Semaphoren wirklich zu verstehen.


    Vielleicht nicht direkt um Semaphoren zu verstehen, sondern Synchronisierung im Allgemeinen. Ich würde aber sagen, es ist im prinzip andersherum. Synchronisierung zu verstehen, und damit die richtige Strategie zur Synchronisierung der Prozesse zu sehen, fürt zur Lösung. Ein paar Denkanstöße:

    • Muss jeglicher Zugriff auf eine geeteilte Resource (den SHM) synchronisiert werden?
    • Muss der SHM bei der Synchronisierung im Ganzen als Einheit gesehen werden? oder gibt es teile die unabhängig voneinenander behandelt weren können/müssen?
    • Gibt es einen Teil des SHM, über den du etwas besonderes weißt, was du bei der Synchronisierung ausnutzen kannst? (Denk dabei an das Server-beendet-flag)




    Also muss das Setzen der Flag noch irgendwie in der while-Schleife passieren.

    Code
    1. while(!want_quit) {
    2. sem_wait(s1);
    3. server();
    4. if(want_quit) {
    5. shared_memory_flag_false_setzen();
    6. }
    7. sem_post(s2);
    8. }


    sem_post ist atomic, aber das Problem ist hierbei, dass ein Signal nach dem if
    unterbrechen kann, sodass nicht sichergestellt ist, dass das Flag gesetzt wird.


    Ich verstehe hier nicht was du meinst. Wenn ein Signal kommt, das behandelt wird, macht das Programm ja nachher dort weiter, wo es unterbrochen wurde. Das Flag würde also gesetzt werden. Bei einem Signal, das nicht behandelt wird, ergibt die Überlegung ohnehin keinen Sinn.


    mfg,
    VaarSuvius

    [SS15, WS15, SS16, WS16: OSUE-Tutor; WS15, WS16: ASE-Tutor; SS16: SEPM-Tutor]

  • Ich habe schon überlegt, ob ich nicht das Flag einfach nach der while-Schleife setzen könnte, allerdings
    dachte ich, das ist doch "ein Writer many Reader" Problem: Ein Server der schreibt und mehrere Clients die lesen.


    Ich habe jetzt noch mehr bezüglich allgemeiner Concurrency recherchiert:
    Laut Stallings ist die dritte Bedingung dafür "If a writer is writing a file, no reader may read it."


    Wird das bei Shared Memory generell benötigt? Wenn nicht, würde das heißen, dass ich die Flag setzen kann. (Was ist wenn eine CPU auf den Speicher schreibt und eine CPU den Speicher gleichzeitig liest)
    Wieso muss ich dann die Kommunikation zwischen Server und den Clients synchonisieren? Meine Antwort wäre, dass es dann hauptsächlich wegen der Race Condition benötigt wird (Request-Response in richtiger Reihenfolge), bzw. wenn beide Prozesse auf den Speicher schreiben (http://beej.us/guide/bgipc/out…multipage/shm.html#shmcon "This concurrent access is almost always a problem when you have multiple writers to a shared object.", Das ist beides bei der Flag nicht der Fall!).






    Code
    1. while(!want_quit) {
    2. sem_wait(s1);
    3. server();
    4. if(want_quit) {
    5. shared_memory_flag_false_setzen();
    6. }
    7. sem_post(s2);
    8. }


    Hierbei meinte ich, dass wenn nach dem if-Statement das Signal behandelt wird, want_quit gesetzt wird,
    daher wird die Schleife nicht noch einmal ausgeführt und das flag wird nicht gesetzt.


    MFG,
    SuperMX


  • Ich habe schon überlegt, ob ich nicht das Flag einfach nach der while-Schleife setzen könnte,


    Das wäre ja schon eine Überlegung, die das Problem löst. Du musst nur noch sicherstellen, dass alle clients auch beenden.



    Naja wie du schon gesagt hast, diese Anforderung bezieht sich auf ein file. Etwas das generell größer ist (und potentiell eine variable größe hat). Wenn da ein Reader dazwischen liest, könnte er einen inkonsistenten Zustand lesen, wo ein teil der Datei neu geschrieben ist und ein anderer noch nicht. Das ist nicht das selbe wie ein einzelnes Bit, Byte oder Wort, das atomar geschrieben und gelesen werden kann. Wie du schon richtig sagst, ginge es hier (bei dem Terminate-flag) nurnoch darum, eine Race Condition zwischen zwei Writer zu vermeiden, die nicht passieren kann, da es nur einen Writer gibt.


    Beim Rest des SHM ist das natürlich anders.




    Hierbei meinte ich, dass wenn nach dem if-Statement das Signal behandelt wird, want_quit gesetzt wird,
    daher wird die Schleife nicht noch einmal ausgeführt und das flag wird nicht gesetzt.


    Ahh, das hatte ich wohl falsch verstanden.


    MFG,
    SuperMX[/QUOTE]

    [SS15, WS15, SS16, WS16: OSUE-Tutor; WS15, WS16: ASE-Tutor; SS16: SEPM-Tutor]

  • Ok!


    Dann stimmt das, und nach meiner Überlegung könnte ich das Abfragen der flag bei den Clients auch ohne Semaphoren implementieren.
    Vielen Dank!