Hallo,
ich möchte von verschiedenen (selbstgeschriebenen) Prozessen auf die
selbe Datei zugreifen. Nach Recherche muss man das mit einem shared mem
mutex machen. Deshalb führe ich beim Start jedes Prozesses folgenden
Code aus:
1
//try to get shared mem
2
int shmid = shmget(SHM_ID, sizeof(pthread_mutex_t), 0666);
Werner schrieb:> Ist das so der richtige Weg?
die Frage ist was du erreichen willst.
Man kann auch ohne Mutex oder ähnlichen dinge gleichzeitig auf eine
Datei zugreifen.
Mehrere Prozesse sollen in der selben Datei verschiedene Stellen ändern
können. In jedem Prozess wird das so gemacht:
- Mutex lock
- Datei neu laden
- Datei ändern
- Datei schreiben
- Mute unlock
Gibt es einen anderen (einfacheren) Weg?
Werner schrieb:> Gibt es einen anderen (einfacheren) Weg?
wenn jeder Prozess an einer anderen Stelle in der Datei rumschreibt,
brauchst du kein Mutex.
Auch muss die Datei nicht ständig geöffnet und geschlossen werden.
Werner schrieb:> Die Prozesse können aber auch Zeilen einfügen oder weglöschen...
davon war bis jetzt keine Rede.
Wenn du so etwas machen willst, dann musst du wohl mit dem Mutex
arbeiten. Die Frage ist aber warum mehre Prozesse in einer Datei
rumschreiben müssen. Eventuell ist es sinnvoll einen 3.Prozess zu haben
der sich um die Datei kümmern und die andere Prozesse kommunizieren mit
dem Datei-Prozess.
Werner schrieb:> Die Prozesse können aber auch Zeilen einfügen oder weglöschen...
Ömmm, wie stellst du dir das vor? Also jetzt nur mal für einen einzelnen
Prozess und ohne das Locking. Ich fürchte, dass das Locking erst dein
Problem Nummer 2 ist.
Das ganze klingt als möchtest du die Datei wie eine Datenbank benutzen.
Wenn du beim Dateiformat flexibel bist: Nimm SQLite. Damit bist du die
ganzen Sorgen los und hast als Bonus noch die Flexibilität von SQL,
Datensicherheit bei Abstürzen, etc. Wenn du den WAL-Modus aktivierst
(siehe Doku) ist das ganze auch noch sehr schnell.
Hermann K. schrieb:> SQLite
Bei konkurrierenden Zugriffen mehrerer Prozesse ist die Performanz
schnell beim Teufel. Aber richtig, alle anderen Probleme sind damit vom
Tisch.
>Ömmm, wie stellst du dir das vor?
Datei in den Speicher lesen, ändern, abspeichern. Umnoch genauer zu
sein: Ich verwende (muss) die libconfig-Bibliothek:
http://www.hyperrealm.com/libconfig/libconfig_manual.html
Die Klasse hat eine readFile- und eine writeFile-Methode...
Werner schrieb:> Mehrere Prozesse sollen in der selben Datei verschiedene Stellen ändern> können.
Tönt nach Unabhängigkeit: soll doch jeder Prozess seine eigene Datei
bekommen.
Dort wo jeder Prozess losgetreten wird, kann davor die eine
Gesamtdatei aufgeteilt werden, nach beenden der Prozesse die Teildateien
wieder zur Gesamtdatei zusammenführen.
Werner schrieb:>>Ömmm, wie stellst du dir das vor?>> Datei in den Speicher lesen, ändern, abspeichern. Umnoch genauer zu> sein: Ich verwende (muss) die libconfig-Bibliothek:>> http://www.hyperrealm.com/libconfig/libconfig_manual.html>> Die Klasse hat eine readFile- und eine writeFile-Methode...
Ah, das heißt, du willst nicht die Datei ändern, sondern sie durch eine
neue ersetzen.
Andreas E. schrieb:> flock wurde ja schon erwähnt.
Das setzt aber eine offene Datei voraus, deren Deskriptor man kennt.
Hier wird aber eine Funktion aufgerufen, die intern eine Datei öffnet,
schreibt und wieder schließt.
Und wie schon gesagt: Hier wird gar nicht eine bestehende Datei
geändert, sondern eine neue erzeugt, die die alte ersetzt. Wenn das zwei
Programme gleichzeitig tun, bringt mir ein flock() nichts, selbst wenn
ich an den Deskriptor rankäme, denn es sind dann zwei verschiedene
Dateien und nicht die selbe.
Man kann Files auch exklusiv erzeugen, dann gewinnt nur einer.
Eine sehr universelle Mutex auf Fileebene ist eine Lock-Directory, weil
mkdir eine atomare Operation ist. Das funktioniert sogar auf
CMD/Shell-Ebene.
Werner schrieb:>>Ömmm, wie stellst du dir das vor?>> Datei in den Speicher lesen, ändern, abspeichern. Umnoch genauer zu> sein: Ich verwende (muss) die libconfig-Bibliothek:>> http://www.hyperrealm.com/libconfig/libconfig_manual.html>> Die Klasse hat eine readFile- und eine writeFile-Methode...
Ehrlich gesagt, ist mir Software wie diese libconfig ziemlich suspekt.
Wie kann es sein, daß eine C++(!)-Software nicht mit STL-Streams
funktioniert, sondern nur mit C's FILE-Pointern? 2016? Echt jetzt?!
Warum mußt Du dieses Zeug benutzen, Vorgabe des Kunden/AG? Ansonsten
böte sich vielleicht der json_parser() aus boost.PropertyTree an. Das
hat mit JSON immerhin ein etabliertes, standardisiertes Dateiformat, das
jenem von libconfig sehr ähnlich, wahrscheinlich sogar kompatibel ist
(das käme auf einen Versuch an). Und außerdem kann das mit
basic_[io]stream aus der STL umgehen, also nicht nur mit Dateien.
Und wo wir schon bei Linux und C++ sind: Linux bietet zu diesem Zweck
die Named Semaphores an, und C++11 bietet einige freundliche Hilfsmittel
mit std::mutex, std::atomic und / oder std::lock_guard.
Sheeva P. schrieb:> Ehrlich gesagt, ist mir Software wie diese libconfig ziemlich suspekt.> Wie kann es sein, daß eine C++(!)-Software nicht mit STL-Streams> funktioniert, sondern nur mit C's FILE-Pointern? 2016? Echt jetzt?!
ich finde die Stream sehr unhandlich. Ich verwende sehr gerne C++ aber
die Streams meiden ich wenn möglich. Sie bringen nicht wirklich Vorteile
wenn man in eine Datei schreiben will.
genauso wie ein printf immer noch sinnvoll ist für eine Formatierung.
FILE-Pointern gehören genauso zu C++ wie auch STL-Streams auch 2016!
Wieso eine Datei benutzen? Wenn es eine handliche Grösse ist (<1GB oder
so), kann man die Datei doch einfach ins RAM laden und darin bearbeiten.
Genau dafür hat man doch die Cache/Memory coherent SMP Rechner von heute
erfunden
Rolf M. schrieb:> Das setzt aber eine offene Datei voraus, deren Deskriptor man kennt.
Das stimmt auch wieder.
A. K. schrieb:> Man kann Files auch exklusiv erzeugen, dann gewinnt nur einer.
Also so:
Peter II schrieb:> Sheeva P. schrieb:>> Ehrlich gesagt, ist mir Software wie diese libconfig ziemlich suspekt.>> Wie kann es sein, daß eine C++(!)-Software nicht mit STL-Streams>> funktioniert, sondern nur mit C's FILE-Pointern? 2016? Echt jetzt?!>> ich finde die Stream sehr unhandlich. Ich verwende sehr gerne C++ aber> die Streams meiden ich wenn möglich. Sie bringen nicht wirklich Vorteile> wenn man in eine Datei schreiben will.
Das ist mir, ehrlich gesagt, vollkommen unverständlich. Streams sind so
ziemlich das Coolste seit geschnittenem Brot:
Jetzt kann ich Instanzen von Ruebennase ausgeben, wohin ich will: in
eine Datei (std::ofstream), einen Puffer (std::ostringstream), ins
Syslog (über eine eigene Klasse, die von std::basic_streambuf abgeleitet
ist), ... mach das doch mal ähnlich elegant und einfach mit
FILE-Pointern.
> genauso wie ein printf immer noch sinnvoll ist für eine Formatierung.
Boost.Format existiert.
> FILE-Pointern gehören genauso zu C++ wie auch STL-Streams auch 2016!
Ja, aber da geht es primär um Abwärtskompatibilität. STL und Boost
nutzen C++-Streams -- und wenn man die volle Leistungsfähigkeit von C++
benutzen kann und will, zumal auf einem PC statt in einer limitierten
uC-Umgebung, sind Streams die bessere Lösung als die primitive Altlast
FILE*.
Rote T. schrieb:> Wieso eine Datei benutzen?
Vermutlich um die Daten zu persistieren.
> Wenn es eine handliche Grösse ist (<1GB oder so), kann man die Datei doch> einfach ins RAM laden und darin bearbeiten. Genau dafür hat man doch die> Cache/Memory coherent SMP Rechner von heute erfunden
Wenn mehrere Prozesse auf die Daten zugreifen müssen und die Daten eine
signifikante Größe haben (mehr als ein paar MB), ist es natürlich
sinnvoll, die Daten in einem Shared Memory vorzuhalten. Aber auch der
muß nach jeder Manipulation gesynct werden. Dabei bieten mmap() (mit
MAP_SHARED), msync() und mprotect() gute Möglichkeiten; da die
Funktionen in der Library des OP aber mit FILE-Pointern oder Dateinamen
arbeiten, geht das nicht.
Karl Käfer schrieb:> Jetzt kann ich Instanzen von Ruebennase ausgeben
Bei FILE*s stößt man an die Beschränkungen von C. Da braucht man
entweder eine eigene Funktion
1
print_ruebennase(FILE*,Ruebennase*)
oder man erweitert printf() (was nur mit register_printf_function() aus
der GNU libc einfach geht).
Wenn man C++ voraussetzen kann, geht so etwas halt einfacher.
> wohin ich will: in eine Datei (std::ofstream), einen Puffer> (std::ostringstream), ins Syslog (über eine eigene Klasse, die von> std::basic_streambuf abgeleitet ist), ... mach das doch mal ähnlich> elegant und einfach mit FILE-Pointern.
FILE* ist auch nur eine abstrakte Schnittstelle. Siehe fmemopen()/
open_memstream() (POSIX) und fopencookie() (GNU und newlib) oder
funopen() (BSD).
Clemens L. schrieb:> Karl Käfer schrieb:>> Jetzt kann ich Instanzen von Ruebennase ausgeben>> Bei FILE*s stößt man an die Beschränkungen von C. Da braucht man> entweder eine eigene Funktion
1
print_ruebennase(FILE*,
2
>Ruebennase*)
oder man erweitert printf() (was nur mit
> register_printf_function() aus der GNU libc einfach geht).
Entschuldige bitte, aber in diesem Thread ging es ausnahmsweise einmal
nicht um C versus C++. ;-)
> Wenn man C++ voraussetzen kann, geht so etwas halt einfacher.
Ebendies war doch bezweifelt worden.
>> wohin ich will: in eine Datei (std::ofstream), einen Puffer>> (std::ostringstream), ins Syslog (über eine eigene Klasse, die von>> std::basic_streambuf abgeleitet ist), ... mach das doch mal ähnlich>> elegant und einfach mit FILE-Pointern.>> FILE* ist auch nur eine abstrakte Schnittstelle. Siehe fmemopen()/> open_memstream() (POSIX) und fopencookie() (GNU und newlib) oder> funopen() (BSD).
Schon klar, aber darum ging es ja nicht. Es ging um C++ auf dem PC --
und warum soll man sich noch mit solchen Limitierungen von C plagen,
wenn man ohnehin C++ benutzt und ausreichende Ressourcen hat, um die
ganze Eleganz und Leistungsfähigkeit von C++, STL (und ggf. Boost)
ausnutzen zu können? Wenn schon, denn schon.
Konrad S. schrieb:>> SQLite> Bei konkurrierenden Zugriffen mehrerer Prozesse ist die Performanz> schnell beim Teufel.
Nur, wenn mehrere Prozesse gleichzeitig in die Datenbank schreiben.
Parallele Lesezugriffe werden parallel abgehandelt (und sind m.W. auch
dann noch konsistent, wenn ein anderer Prozess gleichzeitig am gleichen
Datensatz pfuscht).
Also dann vielleicht doch noch etwas mehr Hintergrundinformation:
Es dreht sich um zwei Linuxdienste, die einen Telnetserver zur
Konfiguration beinhalten. Für jede eingehende Verbindung wird ein
(Thread-)objekt erzeugt. Nun gibt es Kommandos die etwas in die
Konfigurationsdatei schreiben. So kann es natürlich passieren dass
mehrere Threads/Prozesse gleichzeitig auf die Datei zugreifen...
Werner schrieb:> Also dann vielleicht doch noch etwas mehr Hintergrundinformation:>> Es dreht sich um zwei Linuxdienste, die einen Telnetserver zur> Konfiguration beinhalten. Für jede eingehende Verbindung wird ein> (Thread-)objekt erzeugt. Nun gibt es Kommandos die etwas in die> Konfigurationsdatei schreiben. So kann es natürlich passieren dass> mehrere Threads/Prozesse gleichzeitig auf die Datei zugreifen...Wessen Konfigurationsdatei genau wird da beschrieben?
Die des einen Dienstes? Die des anderen? Die des Telnetservers? Oder gar
eine von mehreren Diensten gemeinsam genutzte?