How to Mutex über ein Netzwerk?

8

Ich habe eine Desktop-Anwendung, die in einem Netzwerk ausgeführt wird und jede Instanz verbindet sich mit derselben Datenbank.

Wie kann ich also in dieser Situation einen Mutex implementieren, der für alle laufenden Instanzen gilt, die mit derselben Datenbank verbunden sind?

Mit anderen Worten, ich möchte nicht, dass zwei + Instanzen die gleiche Funktion gleichzeitig ausführen. Wenn die Funktion bereits ausgeführt wird, sollten die anderen Instanzen keinen Zugriff darauf haben.

PS: Die Datenbank-Transaktion löst nicht, weil die Funktion, die ich mutex verwenden möchte, die Datenbank nicht benutzt. Ich habe die Datenbank nur erwähnt, weil sie zum Austausch von Informationen zwischen den laufenden Instanzen verwendet werden kann.

PS2: Die Funktion benötigt etwa 30 Minuten. Wenn also eine zweite Instanz versucht, die gleiche Funktion auszuführen, möchte ich eine nette Nachricht anzeigen, die momentan nicht ausgeführt werden kann, weil Computer 'X' bereits vorhanden ist Ausführen dieser Funktion.

PS3: Die Funktion muss auf dem Client-Rechner verarbeitet werden, daher kann ich keine gespeicherten Prozeduren verwenden.

    
Daniel Silveira 05.11.2009, 18:44
quelle

6 Antworten

2

Ich glaube, Sie suchen nach einer Datenbanktransaktion. Eine Transaktion isoliert Ihre Änderungen von allen anderen Clients.

Aktualisierung: Sie haben erwähnt, dass die Funktion derzeit nicht in die Datenbank schreibt. Wenn Sie diese Funktion mutexen möchten, müssen Sie einen zentralen Speicherort für den aktuellen Mutex-Halter haben. Die Datenbank kann dafür arbeiten - fügen Sie einfach eine neue Tabelle hinzu, die den Computernamen des aktuellen Besitzers enthält. Überprüfen Sie diese Tabelle, bevor Sie Ihre Funktion starten.

Ich denke, dass Ihre Frage Verwirrung stiften kann. Mutexe sollten Ressourcen schützen. Wenn Ihre Funktion nicht auf die Datenbank zugreift, welche gemeinsame Ressource schützen Sie dann?

    
Matt Brunell 05.11.2009 18:48
quelle
0

Setzen Sie den Code innerhalb einer Transaktion entweder - in der App oder besser - in eine gespeicherte Prozedur und rufen Sie die gespeicherte Prozedur auf. Der Transaktionsmechanismus isoliert den Code zwischen den Anrufern.

    
Dani 05.11.2009 18:50
quelle
0

Betrachte umgekehrt eine Nachrichtenwarteschlange. Wie erwähnt, sollte die Datenbank all dies für Sie entweder in Transaktionen oder seriellem Zugriff auf Tabellen verwalten (ala MyISAM).

    
Jé Queue 05.11.2009 18:52
quelle
0

In der Vergangenheit habe ich Folgendes getan:

  1. Erstellen Sie eine Tabelle, die im Grunde zwei Felder hat: funktionsname und is_running
  2. Ich weiß nicht, welche RDBMS Sie verwenden, aber die meisten haben die Möglichkeit, einzelne Datensätze für die Aktualisierung zu sperren. Hier ist ein pseduocode basierend auf Oracle:

    BEGINN TRANS

    SELECT FÜR AKTUALISIERUNG is_running FROM funktionstabelle WHERE funktionsname = 'foo';

    - Überprüfen Sie hier, ob es läuft, wenn nicht, können Sie running auf 'true' setzen

    UPDATE function_table Menge is_running = 'Y' wobei function_name = 'foo';

    COMMIT TRANS

Jetzt habe ich die Oracle PSQL-Dokumentation nicht bei mir, aber Sie bekommen die Idee. Die Klausel "FOR UPDATE" sperrt den Datensatz nach dem Lesen bis zum Commit, sodass andere Prozesse diese SELECT-Anweisung blockieren, bis der aktuelle Prozess festgeschrieben wird.

    
Mike Marshall 05.11.2009 18:55
quelle
0

Sie können Terracotta verwenden, um solche Funktionen zu implementieren, wenn Sie einen Java-Stack haben.

    
Stefan Kendall 05.11.2009 18:55
quelle
0

Auch wenn Ihre Funktion die Datenbank derzeit nicht verwendet, können Sie das Problem mit einer bestimmten Tabelle lösen, um diese Funktion zu synchronisieren. Die Einzelheiten hängen von Ihrer DB und davon ab, wie Isolationsstufen und Sperren gehandhabt werden. Mit SQL Server würden Sie beispielsweise die Transaktionsisolation auf wiederholbares Lesen setzen, einen Wert aus Ihrer Sperrzeile lesen und ihn innerhalb einer Transaktion aktualisieren. Übernehmen Sie die Transaktion erst, wenn Ihre Funktion abgeschlossen ist. Sie können in einer Transaktion in den meisten Datenbanken auch explizite Tabellensperren verwenden, die möglicherweise einfacher sind. Dies ist wahrscheinlich die einfachste Lösung, wenn Sie bereits eine Datenbank verwenden.

Wenn Sie sich aus irgendeinem Grund nicht auf die Datenbank verlassen möchten, könnten Sie einen einfachen Dienst schreiben, der TCP-Verbindungen von Ihrem Client akzeptiert. Jeder Client würde die Berechtigung zum Ausführen anfordern und würde nach dem Beenden eine Antwort zurückgeben. Der Server kann sicherstellen, dass nur ein Client die Berechtigung erhält, gleichzeitig ausgeführt zu werden. Tote Clients würden schließlich die TCP-Verbindung fallenlassen und erkannt werden, solange Sie die richtige Keep Alive-Einstellung haben.

Die von Xepoch vorgeschlagene Lösung für die Nachrichtenwarteschlange würde ebenfalls funktionieren. Sie können etwas wie MSMQ oder Java Message Queue verwenden und haben eine einzelne Nachricht, die als Lauf-Token fungieren würde. Alle Ihre Kunden würden die Nachricht anfordern und sie dann erneut posten, wenn sie fertig sind. Sie riskieren einen Deadlock, wenn ein Client vor dem Reposting stirbt, also müssten Sie eine Logik entwickeln, um dies zu erkennen, und es könnte kompliziert werden.

    
J. Loomis 05.11.2009 19:16
quelle