Nein, der Programmablauf für das Lesegerät ist nicht korrekt. Sie benötigen eine Art Sperrmechanismus, um Schreibvorgänge zu verhindern, während eine oder mehrere Lesevorgänge ausgeführt werden, sowie eine Art Wakeup-Mechanismus, um Leser zu benachrichtigen, wenn ein Schreibvorgang abgeschlossen ist.
Ihr Programmablauf für den Autor (en) ist in Ordnung:
# Initial read of file contents
Obtain lock
Read file
Release lock
# Whenever wishes to modify file:
Obtain lock
Modify file
Signal readers
Release lock
Der Programmablauf für den Leser (s) sollte sein:
# Initial read of file contents
Obtain lock
Read file
Release lock
# Wait and respond to changes in file
On signal:
Obtain lock
Read file
Release lock
Do something with modified file contents
Wenn es nur eine Leser, dann genügt ein Mutex (pthread_mutex_t
) im geteilten Speicher (zugänglich für alle Schreiber und den Leser); Ansonsten empfehle ich stattdessen einen Rwlock (pthread_rwlock_t
). Zum Aufwecken von wartenden Lesern wird eine Zustandsvariable gesendet (pthread_cond_t
). Die Schwierigkeit besteht natürlich darin, diesen gemeinsamen Speicher einzurichten.
Advisory-Datei sperren und die fanotify Schnittstelle ist auch ausreichend. Leser installieren ein fanotify FAN_MODIFY
markieren, und warten Sie einfach auf das entsprechende Ereignis. Autoren müssen nicht zusammenarbeiten, mit Ausnahme der Verwendung einer Advisory-Sperre (die nur dazu dient, Lesern das Lesen zu verweigern, während die Datei geändert wird).
Leider benötigt die Schnittstelle derzeit die CAP_SYS_ADMIN
Fähigkeit, die Sie nicht wollen, dass zufällige CGI-Programme haben.
Advisory Dateisperren und die inotify Schnittstelle genügt, und ich glaube, die am besten geeignet für diesen, wenn beiden Leser und Schreiber öffnen und die Datei für jeden Satz von Operationen schließen. Der Programmablauf für diesen Fall für den Leser (n):
Initialize inotify interface
Add inotify watch for IN_CREATE and IN_CLOSE_WRITE for "file"
Open "file" read-only
Obtain shared/read-lock
Read contents
Release lock
Close "file"
Loop:
Read events from inotify descriptor.
If IN_CREATE or IN_CLOSE_WRITE for "file":
Open "file" read-only
Obtain shared/read-lock
Read contents
Release lock
Close "file"
Do something with file contents
Der Schriftsteller gerade noch ist
# Initial read of file contents
Open "file" for read-only
Obtain shared/read-lock on "file"
Read contents
Release lock
Close "file"
# Whenever wishes to modify file:
Open "file" for read-write
Obtain exclusive/write-lock
Modify file
Release lock
Close "file"
Auch wenn die Autoren nicht in das Schloss erhalten, werden die Leser, wenn eine Benachrichtigung Writer schließt die Datei; Das einzige Risiko besteht darin, dass ein anderer Satz von Änderungen geschrieben wird (durch einen anderen Modifizierer zum Sperren und Zurückweisen), während die Leser die Datei lesen.
Selbst wenn ein Modifizierer die Datei durch eine neue ersetzt, werden die Leser korrekt benachrichtigt, wenn eine neue bereit ist (entweder umbenannt/über die alte verknüpft oder der neue Dateiersteller schließt die Datei). Es ist wichtig zu beachten, dass, wenn die Leser die Datei offen halten, ihre Dateideskriptoren nicht auf magische Weise zu der neuen Datei springen, und sie werden nur die alten (wahrscheinlich gelöschten) Inhalte sehen.
Wenn es aus irgendeinem Grunde ist wichtig, dass Leser und Schreiber nicht schließen Sie die Datei, die Leser noch inotify verwenden können, aber ein IN_MODIFY
Zeichen stattdessen benachrichtigt zu werden, wenn die Datei auf abgeschnitten oder geschrieben ist. In diesem Fall ist es wichtig, sich daran zu erinnern, dass die Leser und Schreiber die neue Datei nicht sehen werden, wenn die Datei dann ersetzt (umbenannt oder gelöscht und neu erstellt) wird, aber auf der alten, jetzt unsichtbar-in-der-Datei ausgeführt wird Dateiinhalte.
Der Programmablauf für den Leser:
Initialize inotify interface
Add inotify watch for IN_MODIFY for "file"
Open "file" read-only
Obtain shared/read-lock
Read contents
Release lock
Loop:
Read events from inotify descriptor.
If IN_CREATE or IN_CLOSE_WRITE for "file":
Obtain shared/read-lock on "file"
Read contents
Release lock
Do something with file contents
Der Programmablauf für den Schriftsteller ist immer noch fast das gleiche:
# Initial read of file contents
Open "file" for read-only
Obtain shared/read-lock on "file"
Read contents
Release lock
Close "file"
Open "file" for read-write
# Whenever writer wishes to modify the file:
Obtain exclusive/write-lock
Modify file
Release lock
Es kann wichtig sein, zu beachten, dass die inotify Ereignisse treten nach der Tat auf. Es gibt normalerweise eine kleine Latenz, die von der Auslastung der Maschine abhängen kann. Wenn eine schnelle Antwort auf Dateiänderungen wichtig ist, damit das System ordnungsgemäß funktioniert, müssen Sie möglicherweise stattdessen eine Mutex- oder Rwlock- und eine Bedingungsvariable im Shared Memory-Ansatz verwenden.
Nach meiner Erfahrung sind diese Latenzen tendenziell kürzer als das typische menschliche Reaktionsintervall. Daher denke ich - und ich schlage vor, Sie tun es auch - die Inotify-Schnittstelle schnell und zuverlässig genug zu menschlichen Zeitskalen; Nicht so bei Millisekunden- und Sub-Millisekunden-Maschinen-Zeitskalen.
Sie könnten einen Semaphor anstelle eines Mutex verwenden. – Riley
Es scheint mir, dass Sie Interprozesskommunikation wollen. Ich schlage vor, auf linux Named Pipes oder [ZeroMQ] (http://czmq.zeromq.org/) zu lesen, anstatt auf Ihrem Ad-hoc-Schema. – orlp
Keiner Ihrer Kommentare adressierte die von mir aufgezeigte Race Condition. Ich weiß von Semaphoren, ich weiß von IPC. –