Linux: Dateizugriff von mehreren Prozessen

Gast #4441297
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
Gast #4441315
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?
Gast #4441324
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.
#4441336
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.
Gast #4441369
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.
#4441408
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.
#4441438
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.
#4441544
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.
Gast #4441564
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!
Gast #4441698
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*.
Gast #4441780
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.
#4441910
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).
Gast #4442109
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.
Gast #4443245
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...
#4445454
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren