Forum: PC-Programmierung Linux: Dateizugriff von mehreren Prozessen


von Werner (Gast)


Lesenswert?

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);
3
4
  if (shmid == -1) {
5
    //does not exist, we have to initialize
6
    shmid = shmget(SHM_ID, sizeof(pthread_mutex_t), 0666 | IPC_CREAT);
7
    cout << "SHM created, ID " << shmid << endl;
8
9
    mutex = (pthread_mutex_t *) shmat(shmid, NULL, 0);
10
    pthread_mutexattr_t mattr;
11
    pthread_mutexattr_init(&mattr);
12
    pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE_NP);
13
    pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
14
    pthread_mutex_init(mutex, &mattr);
15
  }
16
  else {
17
    cout << "SHM found, ID " << shmid << endl;
18
    mutex = (pthread_mutex_t *) shmat(shmid, NULL, 0);
19
  }

Ist das so der richtige Weg?

Werner

von Peter II (Gast)


Lesenswert?

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.

von Werner (Gast)


Lesenswert?

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?

von Peter II (Gast)


Lesenswert?

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.

von Werner (Gast)


Lesenswert?

Die Prozesse können aber auch Zeilen einfügen oder weglöschen...

von Peter II (Gast)


Lesenswert?

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.

von Konrad S. (maybee)


Lesenswert?

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.

von Hermann K. (r2d2)


Lesenswert?

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.

von Konrad S. (maybee)


Lesenswert?

Hermann K. schrieb:
> SQLite

Bei konkurrierenden Zugriffen mehrerer Prozesse ist die Performanz 
schnell beim Teufel. Aber richtig, alle anderen Probleme sind damit vom 
Tisch.

von Werner (Gast)


Lesenswert?

>Ö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...

von Konrad S. (maybee)


Lesenswert?

Schau dir mal flock() an:
1
man 2 flock

von Kommandozeile vor dem Frühstück für Alle! (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Sind Mutexe an Stelle klassischer File Locks nicht etwas von hinten 
durch die Brust ins Auge?

von Andreas E. (hismastersvoice)


Lesenswert?

flock wurde ja schon erwähnt.
Lies mal in

http://poincare.matf.bg.ac.rs/~ivana//courses/ps/sistemi_knjige/pomocno/apue.pdf

(Steve Richards "Advanced Programming in the Unix Environment"

Kapitel 14.3 "Record Locking".

Das sollte all Deine Fragen beantworten.

von Rolf M. (rmagnus)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Sheeva P. (sheevaplug)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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!

von 🍅🍅 🍅. (tomate)


Lesenswert?

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

von Konrad S. (maybee)


Lesenswert?

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:
1
open( LOCKFILE, O_CREAT | O_EXCL, 0600 )

von Karl Käfer (Gast)


Lesenswert?

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:
1
#include <iostream>
2
#include <string>
3
4
using namespace std;
5
6
class Ruebennase {
7
private:
8
    int ruebe;
9
    string nase;
10
public:
11
    Ruebennase(int ruebe, string nase)
12
        : ruebe(ruebe), nase(nase)
13
    {}
14
    friend ostream& operator<<(ostream& os, Ruebennase& rn);
15
};
16
17
ostream& operator<<(ostream& os, Ruebennase& rn) {
18
    os << "Ruebennase.ruebe = " << rn.ruebe
19
       << ", Ruebennase.nase = \"" << rn.nase << "\"";
20
    return os;
21
}

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*.

von Karl Käfer (Gast)


Lesenswert?

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.

von Clemens L. (c_l)


Lesenswert?

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).

: Bearbeitet durch User
von Karl Käfer (Gast)


Lesenswert?

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.

von S. R. (svenska)


Lesenswert?

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).

von Werner (Gast)


Lesenswert?

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...

von Peter II (Gast)


Lesenswert?

Werner schrieb:
> Also dann vielleicht doch noch etwas mehr Hintergrundinformation:

warum sind es 2 Prozesse?

von Konrad S. (maybee)


Lesenswert?


von Mark B. (markbrandis)


Lesenswert?

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?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.