Hallo zusammen,
Ich habe hier schon mehrere Beiträge über das Thema gelesen, jedoch trug
keiner zur Lösung meines Problems bei.
Und war möchte ich den, von einem anderen Programm(programm 1) an der
Adresse (z.b 0x7ef1df30) , gespeicherten Wert auslesen lassen und
weiter nutzen.
Die Adresse wird nach Start des Programms 1 in eine Datei geschrieben
und dann vom Programm 2(mehrere Programme) eingelesen, sodass Programm
2 weiß wo der Wert steht. Hatte erst an die Einbindung der Programme
ineinander gedacht. Da es aber wichtig ist, das alle Programme zur
gleichen Zeit den gleichen Wert auslesen, fällt das schon mal flach.
Um zu sehen, ob der Wert ausgelesen wurde habe ich ihn einfach mal
testweise ausgeben wollen.
1
#include<stdio.h>
2
intmain(){
3
Int*adresse=(int*)(0x7ef1df30);
4
intwert=*adresse;//Variante 1
5
printf(" %i\n",*adresse);
6
printf(" %i\n",wert);//variante 1
7
return0;
8
}
Ausgegeben bekomme ich jedoch nur 0
Wo liegt der Fehler?
Gruß
Lucien
Lu schrieb:> Und war möchte ich den, von einem anderen Programm(programm 1) an der> Adresse (z.b 0x7ef1df30) , gespeicherten Wert auslesen lassen und> weiter nutzen.> Die Adresse wird nach Start des Programms 1 in eine Datei geschrieben> und dann vom Programm 2(mehrere Programme) eingelesen,
Was jetzt, in eine Speicherstelle im RAM oder in einer Datei? Unter
normalen Betriebssystemen wie Linux, Windows kannst du nicht einfach an
eine beliebige Speicherstelle schreiben, und schon gar nicht so dass
andere Programme das sehen können.
Hallo,
Int sollte natürlich klein geschrieben sein... Sorry das mach die
Autokorrektur ganz schnell
Also laufen soll das ganze unter Raspbian.
Wie schon beschrieben wird die von Programm 1 zum Programmstart
festgelegte speicheradresse ausgelesen und in eine Datei geschrieben
diese können andere Programme dann einlesen und so erfahren an welcher
Adresse der Wert gespeichert wird.
Da sich der Wert alle 0,1 sec ändert ist das Schreiben in eine Datei die
immer wieder überschrieben wird keine Option(zieht zu viel
Prozessorleistung). Also dachte ich, wenn allen Programmen der
speicherort bekannt ist könnten sie die Werte von dort auslesen.
Hm. Das hört sich nach einem Wert von einem angeschlossenen Sensor an.
Da würde ich raten, sich mit Treiberprogrammierung zu beschäftigen. Eine
andere Möglichkeit wäre Interprozess-Kommunikation.
Ich würde aber gleichzeitig sehr davon abraten, eine Lösung an einer
MMU oder dem OS vorbei zu hacken. Im allgemeinen wird so eine Lösung
vermutlich ohnehin zu einem erheblichen Teil die gleichen Kenntnisse
erfordern wie sie die Treiberprogrammierung bzw. die
Interprozess-Kommunikation erfordert; und sei es nur um diese nicht zu
stören.
Als letztes rate ich, falls Du mit dieser Antwort nichts anfangen kannst
oder willst, mal das ganze Problem zu schildern. Das gebietet ohnehin
die Höflichkeit (und die Netiquette).
Neben dem * gibt es auch noch &, welches die Adresse ausgibt.
Ich habe die Erfahrung gemacht, dass bei fprint manchmal diese
"Umleitungen" nicht funktionieren, daher besser die Adresse in ein
normales int übertragen und dieses ausgeben.
versuche es mal mit
int adr = &wert; //speichert die Adresse von wert in adr.
oder
int*adr = &wert;
fprint(adr);
Lu schrieb:> Also dachte ich, wenn allen Programmen der> speicherort bekannt ist könnten sie die Werte von dort auslesen.
Wenn das ginge, könnte ja ein bösartiges Programm ("Virus") einfach so
in den Speicher aller anderen Programme reinschreiben und Nutzerdaten
abgreifen. Alle modernen Betriebssysteme verhindern das, jedes Programm
hat seinen eigenen Adressraum (virtueller Speicher) von 0 bis 2^32-1
(bzw. 2^64-1 bei 64bit-Systemen); wenn ein Programm auf Adresse X etwas
schreibt, und ein anderes Programm Adresse X ausliest, sind es
tatsächlich zwei komplett unterschiedliche Speicherstellen.
Um Daten zwischen Prozessen auszutauschen gibt es sog. IPC (Inter
Process Communication). Unter Linux geht das z.B. über Pipes, FIFO's,
Unix Sockets, TCP Sockets. Shared Memory ist für so etwas einfaches
vielleicht etwas übertrieben.
Ergo70 schrieb:> Also dachte ich, wenn allen Programmen der speicherort bekannt ist> könnten sie die Werte von dort auslesen.>> Nein. Dafür gibt es shared memory.
Das klingt vielversprechend! Damit kann ich was anfangen.
Danke!
Lu schrieb:> Das klingt vielversprechend! Damit kann ich was anfangen.> Danke!
Da musst du aber auf Deadlocks und inkonsistente Daten aufpassen und mit
Thread-Synchronisation arbeiten (Semaphores usw). Da das ziemlich
kompliziert sein kann, wäre für diese anscheinend simple Aufgabe z.B.
ein Unix Socket deutlich einfacher.
Dr. Sommer schrieb:> Lu schrieb:> Also dachte ich, wenn allen Programmen der> speicherort bekannt ist könnten sie die Werte von dort auslesen.>> Wenn das ginge, könnte ja ein bösartiges Programm ("Virus") einfach so> in den Speicher aller anderen Programme reinschreiben und Nutzerdaten> abgreifen. Alle modernen Betriebssysteme verhindern das, jedes Programm> hat seinen eigenen Adressraum (virtueller Speicher) von 0 bis 2^32-1> (bzw. 2^64-1 bei 64bit-Systemen); wenn ein Programm auf Adresse X etwas> schreibt, und ein anderes Programm Adresse X ausliest, sind es> tatsächlich zwei komplett unterschiedliche Speicherstellen.> Um Daten zwischen Prozessen auszutauschen gibt es sog. IPC (Inter> Process Communication). Unter Linux geht das z.B. über Pipes, FIFO's,> Unix Sockets, TCP Sockets. Shared Memory ist für so etwas einfaches> vielleicht etwas übertrieben.
Mag wohl sein das man dann mit Kanonen auf Spatzen schießt, aber ich
werde es mal probieren, das erweitert ja schließlich den Horizont
Lu schrieb:> Mag wohl sein das man dann mit Kanonen auf Spatzen schießt
Shared Memory ist eine Kanone, Pipes, Fifos, Unix-Sockets sind
Jagdgewehre :-)
Alternativ überlege dir, ob es wirklich zwei Programme sein müssen und
sich die Funktionalität nicht in eines integrieren lässt.
Lu schrieb:> Hatte erst an die Einbindung der Programme> ineinander gedacht. Da es aber wichtig ist, das alle Programme zur> gleichen Zeit den gleichen Wert auslesen, fällt das schon mal flach.
Was heißt "alle Programme" - muss das Programm explizit mehrfach
gleichzeitig gestartet werden können?
Lu schrieb:> Da es aber wichtig ist, das alle Programme zur> gleichen Zeit den gleichen Wert auslesen,
Das ist die eigentliche Herausforderung. Auch, wenn ein Programm
tatsächlich fremden Speicher lesen könnte. Ich fürchte, man kann das
nicht garantieren. Mit einer POSIX message queue pro Programm2 könnte
Programm1 zumindest abfragen, ob alle Programm2 den aktuellen Wert
gelesen haben. Aber irgendwie sieht auch nicht richtig aus.
Obwohl es unter Linux durchaus geht: lieber nicht, sobald der Sensorwert
zufällig 0xdeafbeef wird, schaltest du die Kühlwasserpumpen für den
Reaktor ab ;)
Helmut S. schrieb:> Gibt es denn keine Peripherieregister/display-memory die man> beschreiben und lesen kann um z. B. 4Bytes zu "verstecken"?
Und wie würdest du an die die dran kommen als normales
Anwendungsprogramm?
Dr. Sommer schrieb:> Helmut S. schrieb:>> Gibt es denn keine Peripherieregister/display-memory die man>> beschreiben und lesen kann um z. B. 4Bytes zu "verstecken"?>> Und wie würdest du an die die dran kommen als normales> Anwendungsprogramm?
Bei einem embededded ARM-processor schreibt man doch auch oft auf die
Peripherie-Register. Dafür gibt es doch bestimmt auch beim Raspberry PI
eine Möglichkeit(Treiber?).
Helmut S. schrieb:> Dafür gibt es doch bestimmt auch beim Raspberry PI eine> Möglichkeit(Treiber?).
Ja, im Kernel. aber das sieht nicht nach Kernel Code aus. Wäre ziemlich
absurd, extra einen Treiber zu schreiben, der Daten in einem Peripherie
Register versteckt, nur damit Programme darüber kommunizieren können.
Wenn man es schon schafft ein Programm mit einem Kernel Treiber
kommunizieren zu lassen, schafft man es 10x zwei Programme ganz normal
über Pipes & Co kommunizieren zu lassen. Das ist nämlich genau dafür da.
Helmut S. schrieb:> Dr. Sommer schrieb:>> Helmut S. schrieb:>>> Gibt es denn keine Peripherieregister/display-memory die man>>> beschreiben und lesen kann um z. B. 4Bytes zu "verstecken"?>>>> Und wie würdest du an die die dran kommen als normales>> Anwendungsprogramm?>> Bei einem embededded ARM-processor schreibt man doch auch oft auf die> Peripherie-Register. Dafür gibt es doch bestimmt auch beim Raspberry PI> eine Möglichkeit(Treiber?).
Genau. Sowas machen Treiber. Das wäre dann eine kompliziertere und
unflexiblere Variante von dem, was man auch mit Shared Memory machen
könnte.
Bauform B. schrieb:> Lu schrieb:>> Da es aber wichtig ist, das alle Programme zur>> gleichen Zeit den gleichen Wert auslesen,>> Das ist die eigentliche Herausforderung.
Absolut richtig, denn dazu müssen die Lesevorgänge synchronisiert werden
-- insbesondere dann, wenn sich der betreffende Wert alle 0,1 Sekunden
ändern kann.
> Mit einer POSIX message queue pro Programm2 könnte> Programm1 zumindest abfragen, ob alle Programm2 den aktuellen Wert> gelesen haben. Aber irgendwie sieht auch nicht richtig aus.
Stimmt. Da aber auch andere vor solchen oder ähnlichen Anforderungen
stehen, gibt es für sowas einen eigenen Namen, nämlich Publish-Subscribe
oder kurz Pubsub, und natürlich auch entsprechende fertige Software wie
LMAX Disruptor, ZeroMQ, oder auch Apache Kafka. Ich selbst würde daher
vermutlich Redis' oder ZeroMQs Pubsub-Funktionen benutzen --
insbesondere Redis könnte hier je nach Anwendungsfall noch einige
interessante Möglichkeiten bieten, sonst ZeroMQ.
Sheeva P. schrieb:> natürlich auch entsprechende fertige Software wie> LMAX Disruptor, ZeroMQ, oder auch Apache Kafka
Photonentorpedos auf Amöben? Man tippe einfach mal "man 7 unix" ein. Da
gibt's sogar Beispielcode:
http://man7.org/linux/man-pages/man7/unix.7.html
Wenn man das asynchron macht, kann man auch beliebig viele "Clients"
gleichzeitig versorgen. Braucht keine zusätzliche Software außer dem
Linux Kernel, ist trivial einzurichten, braucht keine Synchronisierung
per Semaphore o.ä., pfuscht nicht irgendwie im Speicher rum, über die
Dateinamen der Socket-Datei ist das ganze sogar recht transparent für
den Nutzer.
Das heißt natürlich nicht dass Kafka & Co nicht auch sinnvoll sein
können, aber die Anforderungen sehen bis jetzt nicht so aus...
Dr. Sommer schrieb:> Sheeva P. schrieb:>> natürlich auch entsprechende fertige Software wie>> LMAX Disruptor, ZeroMQ, oder auch Apache Kafka>> Photonentorpedos auf Amöben? Man tippe einfach mal "man 7 unix" ein. Da> gibt's sogar Beispielcode:
Das sind Photonentorpedos mit Ruhemasse Null! Mit sowas wie ZeroMQ
bekommt er gleich Layer 4 und 5 für die er sich ansonsten die Finger mit
fehlerträchtigem langweiligem Boilerplate blutig programmieren müsste
wenn er mit nackten sockets rummachen wollte.
Dr. Sommer schrieb:> Sheeva P. schrieb:>> natürlich auch entsprechende fertige Software wie>> LMAX Disruptor, ZeroMQ, oder auch Apache Kafka>> Photonentorpedos auf Amöben? Man tippe einfach mal "man 7 unix" ein. Da> gibt's sogar Beispielcode:>> http://man7.org/linux/man-pages/man7/unix.7.html>> Wenn man das asynchron macht, kann man auch beliebig viele "Clients"> gleichzeitig versorgen. Braucht keine zusätzliche Software außer dem> Linux Kernel, ist trivial einzurichten, braucht keine Synchronisierung> per Semaphore o.ä., pfuscht nicht irgendwie im Speicher rum, über die> Dateinamen der Socket-Datei ist das ganze sogar recht transparent für> den Nutzer.
UNIX Domain Sockets dienen der Kommunikation zwischen zwei Prozessen,
der TO sucht jedoch etwas zur Kommunikation zwischen einem Senderprozeß
mit mehreren Empfängerprozessen. Für haargenau diesen Anwendungsfall
gibt es den besagten Publish-Subscribe-Mechanismus, wie ihn die von mir
genannten Bibliotheken und Programme implementieren.
Wenn wir schon bei den traditionellen UNIX-Technologien bleiben wollen,
erscheint mir POSIX Shared Memory (man 7 shm_overview) viel sinnvoller.
Damit können die beteiligten Prozesse den gewünschten Speicher direkt
mit mmap(2) in ihren Speicherraum mappen und unmittelbar wie auf eine
normale Variable davon lesen bzw. darauf schreiben.
Klar, UNIX Domain Sockets würden auch gehen. Aber dann muß der arme TO
sich manuell um seine Dateideskriptoren für die einzelnen
Client-Verbindungen kümmern, und das ist aufwändig und fehleranfällig.
Du hast natürlich Recht, daß das dann nicht mehr als einen UNIX-Kernel
braucht, aber was soll der Geiz? ZeroMQ und Redis sind in den
Paketrepositories von Debian, Raspbian und Ubuntu bereits enthalten und
nur einen Aufruf von apt(8) entfernt.
Dafür bieten ZeroMQ und Redis gleich auch noch weitere Funktionen wie
zum Beispiel Netzwerktransparenz und im Falle von Redis sogar noch viel
mehr. Sowohl ZeroMQ als auch Redis sind sehr leicht zu benutzen und
kümmern sich vollautomatisch um all das, was Du im Falle von UNIX
Domain Sockets alles manuell machen müsstest.
Insofern ist die Frage, warum der TO eine prinzipbedingt nicht
sonderlich gut geeignete Technologie wie UNIX Domain Sockets aufbohren
sollte, wenn gleichzeitig genau für diesen Anwendungsfall vorgesehene
Technologien wie ZeroMQ und Redis mit wenigen Handgriffen verfügbar
sind. ;-)
Ergo70 schrieb:> Also dachte ich, wenn allen Programmen der speicherort bekannt ist> könnten sie die Werte von dort auslesen.>> Nein. Dafür gibt es shared memory.
Man kann auch ganz normale Dateien vereinbaren, das ist flexibler. Mit
Ramdisk, wenn es schnell gehen soll . Damit hat man so etwas wie
Datenbausteine bei einer SPS.
Ich habe ein ganzes Steuerungsystem aus vielen kleinen Programmen, die
auf diese Weise miteinander kommunizieren und mit recht
unterschiedlicher Hardware arbeiten können.
Sheeva P. schrieb:> und das ist aufwändig und fehleranfällig.
In dem Beispiel war das nicht so kompliziert... Rate mal was redis nutzt
um sich mit lokalen Servern zu verbinden - richtig, Unix Sockets :-) die
kann man übrigens auch sehr leicht Netzwerk Transparent machen indem man
sie mit AF_INET erstellt...
Jobst Q. schrieb:> Ergo70 schrieb:>> Also dachte ich, wenn allen Programmen der speicherort bekannt ist>> könnten sie die Werte von dort auslesen.>>>> Nein. Dafür gibt es shared memory.>> Man kann auch ganz normale Dateien vereinbaren, das ist flexibler. Mit> Ramdisk, wenn es schnell gehen soll.
Äh... bitte entschuldige, aber alle halbwegs modernen Betriebssysteme
halten den Inhalt von Dateien ohnehin in einem Dateisystempuffer, also
in-memory. Sogar dann, wenn man ein fflush(3) macht -- um die
Synchronisation mit der Persistenzschicht zu erreichen, braucht es ein
fsync(2). Da nutzt Dir die Ramdisk leider gar nichts. ;-)
> Ich habe ein ganzes Steuerungsystem aus vielen kleinen Programmen, die> auf diese Weise miteinander kommunizieren und mit recht> unterschiedlicher Hardware arbeiten können.
Naja, Shared Memory, UNIX Domain Sockets, POSIX Message Queues und alle
anderen traditionellen Arten der Interprozeßkommunikation funktionieren
ebenso auf unterschiedlichsten Hardwareplattformen wie Redis und ZeroMQ.
Darüber hinaus kann man sowas natürlich trotzdem machen, wenn man sich
große Latenzen, wenig Durchsatz und verlorene Writes leisten kann.
Dr. Sommer schrieb:> In dem Beispiel war das nicht so kompliziert...
Logisch, die Beispiele beziehen sich aber auch nur auf die Verwendung
genau einer Verbindung zwischen genau einem Client und einem Server.
Aber wenn Du UNIX Domain Sockets ins Feld führst reden wir von n
Verbindungen zwischen n Clients und besagtem Server.
Also muß dieser Server die Verbindungen seiner Clients irgendwie
verwalten, und da der Server niemals davon ausgehen kann, daß alle
Clients konnektiert und verfügbar sind und zudem allesamt korrekt
funktionieren, müßte er seine Client-Verbindungen einzeln und also
dynamisch verwalten. Mit Disconnects, Abstürzen, Race Conditions und
Vollauslastungen seiner Clients... ;-)
Traditionelle Implementierungen haben für jede Verbindung mit fork(2)
einen neuen Prozeß erzeugt (was dank Copy-On-Write zunächst relativ
unaufwändig war), moderne starten einen Thread (was noch unaufwändiger
ist, weil kein neuer Speicherraum allokiert werden muß), und unter Linux
benutzen sie eh heutzutage alle intern den clone(2)-Syscall. Das würde
aber bedeuten, daß Du am Ende etliche Prozesse oder Threads
synchronisieren mußt.
> Rate mal was redis nutzt> um sich mit lokalen Servern zu verbinden - richtig, Unix Sockets :-) die> kann man übrigens auch sehr leicht Netzwerk Transparent machen indem man> sie mit AF_INET erstellt...
Meine Güte, ja. Aber das ist doch genau mein Punkt: Redis macht genau
das, und zwar fertig, vielfach getestet und für produktionsstabil
befunden, was Du lieber von Hand implementiert sehen möchtest. Zudem ist
der Performance-Impact bei lokalen Verbindungen zwischen Redis-Client
und Redis-Server nahe null, und zwar gerade weil die lokalen
Verbindungen über einen UNIX Domain Socket gehen.
Ebenso funktioniert auch ZeroMQ natürlich mit UNIX Domain Sockets -- und
ist dabei je nach Socket-Library angeblich sogar schneller als
klassische AF_UNIX Sockets. Auch ZeroMQ kümmert sich professionell und
selbständig, vielfach getestet und produktionsstabil um alles, was Du
aufwändig alles manuell implementieren willst.
Nebenbei bringen alle genannten Pubsub-Implementierungen schon
Fähigkeiten mit, die jede Eigenimplementierung erst einmal
implementieren müßte -- und zwar ohne, daß ich mir Gedanken über
Byteorders, Programmiersprachen, oder Protokolle machen müßte. Zeig' mir
sowas mal mit UNIX Domain Sockets, dann können wir gerne weiterreden.
;-)
Uns sei bitte nicht böse, wenn ich noch einmal frage: warum sollte ich
mir Arbeit machen, wenn es haargenau diesen Anwendungsfall bereits
performant, stabil, fertig und getestet gibt?
Sheeva P. schrieb:> Uns sei bitte nicht böse, wenn ich noch einmal frage: warum sollte ich> mir Arbeit machen, wenn es haargenau diesen Anwendungsfall bereits> performant, stabil, fertig und getestet gibt?
Weil es bei den (bis jetzt bekannten) Anforderungen massiver Overkill
ist, und eine Eigenimplementation nicht so schwierig ist. Auch die
Unterstützung mehrerer Clients gleichzeitig (wo war die nochmal
gefordert?) ist nicht so schwierig, man kann das auch asynchron mit
select() machen, dann spart man sich die Thread Synchronisation. Es gibt
auch so was wie sportlichen Ehrgeiz, nicht jeder braucht eine super
performante Fertig-Library um 40 Bytes pro Sekunde zu übertragen. Aber
ja, heutige Programmierer können ja nur Libraries zusammen kopieren :-)
Das viel beschriene PubSub-Modell liefert der Kernel gratis mit: publish
ist listen (), subscribe ist connect().
Sheeva P. schrieb:> Wenn wir schon bei den traditionellen UNIX-Technologien bleiben wollen,> erscheint mir POSIX Shared Memory (man 7 shm_overview) viel sinnvoller.> Damit können die beteiligten Prozesse den gewünschten Speicher direkt> mit mmap(2) in ihren Speicherraum mappen und unmittelbar wie auf eine> normale Variable davon lesen bzw. darauf schreiben.
Der Nachteil ist, dass er sich dann mit Synchronisation beschäftigen
muss. Sockets oder Pipes haben den Vorteil, dass das entfällt.
> Klar, UNIX Domain Sockets würden auch gehen. Aber dann muß der arme TO> sich manuell um seine Dateideskriptoren für die einzelnen> Client-Verbindungen kümmern, und das ist aufwändig und fehleranfällig.
Naja, ein Array mit Dateideskriptoren und selct oder poll sind nun keine
Raketenwissenschaft und zum Lernen, wie so ein System funktioniert (was
nach eigenem Bekunden ja auch mit sein Ziel ist) durchaus geeignet.
> Dafür bieten ZeroMQ und Redis gleich auch noch weitere Funktionen wie> zum Beispiel Netzwerktransparenz und im Falle von Redis sogar noch viel> mehr.
Sockets bieten auch Netzwerktransparenz, wenn man TCP- oder UDP-Sockets
statt UNIX-Domain-Sockets nimmt.
Dr. Sommer schrieb:> Weil es bei den (bis jetzt bekannten) Anforderungen massiver Overkill> ist, und eine Eigenimplementation nicht so schwierig ist.
Dem "Eigenimplementierung nicht so schwierig" steht gegenüber daß bei
ZeroMQ die Eigenimplementierung gar nicht erst erforderlich ist da man
den code den man sonst selbst schreiben müsste einfach aus ner gut
getesteten lib hinzulinkt.
> Overkill
Nein. Der zu schreibende Code wird kleiner, der Overhead des extrem
leichtgewichtigen ZeroMQ (welches wahrscheinlich aufgrund seiner
Allgegenwart¹ eh schon installiert ist) ist also kleiner als null.
--
¹) siehe Bild
Dr. Sommer schrieb:> Sheeva P. schrieb:>> Uns sei bitte nicht böse, wenn ich noch einmal frage: warum sollte ich>> mir Arbeit machen, wenn es haargenau diesen Anwendungsfall bereits>> performant, stabil, fertig und getestet gibt?>> Weil es bei den (bis jetzt bekannten) Anforderungen massiver Overkill> ist, und eine Eigenimplementation nicht so schwierig ist.
Ok, Junge, zeig' mir mal Deine Eigenimplementierung, und dann halten wir
meine daneben. Na los, trau' Dich.
> Auch die> Unterstützung mehrerer Clients gleichzeitig (wo war die nochmal> gefordert?)
In diesem Thread. Lesen bildet, probier's aus.
> Es gibt> auch so was wie sportlichen Ehrgeiz, nicht jeder braucht eine super> performante Fertig-Library um 40 Bytes pro Sekunde zu übertragen.
NIH existiert.
> Aber ja, heutige Programmierer können ja nur Libraries zusammen kopieren
Muß ich mir das nach dreißig Jahren System- und Kernelentwicklung von
einem sagen lassen, der lieber irgendwelchen händischen Unsinn prokelt
statt eine getestete und stabile Software zu benutzen? I think not.
> Das viel beschriene PubSub-Modell liefert der Kernel gratis mit: publish> ist listen (), subscribe ist connect().
Erzähl doch keinen Unsinn. Komm, Junge, laß' Code sprechen. ;-)
Was hindert den TO eigentlich daran, die Daten in die Datei zu
schreiben, statt nur deren Adresse?
Und was hindert den TO eigentlich daran, eine passend dimensionierte
Datei (in /tmp) mit mmap() und MAP_SHARED in zwei Prozessen zu mappen
und genau das zu erreichen, was er ursprünglich wollte?
S. R. schrieb:> Was hindert den TO eigentlich daran, die Daten in die Datei zu> schreiben, statt nur deren Adresse?
Was hindert den TO eigentlich daran, die Daten in die Datei zu
schreiben, statt nur deren Adresse?
In der Aufgabe würde 10 mal je Sekunde eine Datei geschrieben. Das ginge
vielleicht mit RAM-Disk. Allerdings ob da z. B. 10 Programme 10mal pro
Sekunde auf diese Datei zugreifen können ist fraglich.
Die normale FLASH-Speicherkarte würde wahrscheinlich einen Dauerbetrieb
über Monate hinweg nicht überleben.
Helmut S. schrieb:> Das ginge vielleicht mit RAM-Disk.
Dafür nimmt man sowas, richtig.
Helmut S. schrieb:> Die normale FLASH-Speicherkarte würde wahrscheinlich einen Dauerbetrieb> über Monate hinweg nicht überleben.
Dafür gibt es einen Plattencache.
S. R. schrieb:> Helmut S. schrieb:>> Das ginge vielleicht mit RAM-Disk.>> Dafür nimmt man sowas, richtig.
Finde ich nur irgendwie recht umständlich, einerseits für das System,
das dann immer den Umweg über ein Dateisystem gehen muss, andererseits
für den Benutzer, der erstmal eine Ramdisk einrichten muss.
> Helmut S. schrieb:>> Die normale FLASH-Speicherkarte würde wahrscheinlich einen Dauerbetrieb>> über Monate hinweg nicht überleben.>> Dafür gibt es einen Plattencache.
Der wird aber regelmäßig (unter Linux soweit ich weiß einmal pro
Sekunde) auf das Medium raussynchronisiert.
Sheeva P. schrieb:>> Man kann auch ganz normale Dateien vereinbaren, das ist flexibler. Mit>> Ramdisk, wenn es schnell gehen soll.>> Äh... bitte entschuldige, aber alle halbwegs modernen Betriebssysteme> halten den Inhalt von Dateien ohnehin in einem Dateisystempuffer, also> in-memory. Sogar dann, wenn man ein fflush(3) macht -- um die> Synchronisation mit der Persistenzschicht zu erreichen, braucht es ein> fsync(2). Da nutzt Dir die Ramdisk leider gar nichts. ;-)
Eine Ramdisk ist trotzdem schneller, ua weil sie das ganze caching nicht
braucht. Die fflush und fsync Funktionen kehren da sofort zurück, weil
sie nichts zu tun haben.
Eine Datei hat gegenüber dem shared memory den Vorteil, dass sie viel
einfacher zu handhaben ist und ohne Aufwand kopiert oder eingelesen
werden kann.
>> Ich habe ein ganzes Steuerungsystem aus vielen kleinen Programmen, die>> auf diese Weise miteinander kommunizieren und mit recht>> unterschiedlicher Hardware arbeiten können.>> Naja, Shared Memory, UNIX Domain Sockets, POSIX Message Queues und alle> anderen traditionellen Arten der Interprozeßkommunikation funktionieren> ebenso auf unterschiedlichsten Hardwareplattformen wie Redis und ZeroMQ.
Ich meinte mit Hardware nicht die Plattform, sondern die Peripherie.
Also dass es für die meisten Programme egal ist, woher die Daten kommen
und wohin sie gehen, ob SPS, GPIOs, RS485-Module, SD-Karte, Netzwerk
usw. Um auf Werte oder einzelne Bits zuugreifen, werden nur Nummern für
die Datei und die Adresse in der Datei gebraucht.
Rolf M. schrieb:> Finde ich nur irgendwie recht umständlich, einerseits für das System,> das dann immer den Umweg über ein Dateisystem gehen muss, andererseits> für den Benutzer, der erstmal eine Ramdisk einrichten muss.
Bei Raspbian, und darum geht es ja hier, gibt es schon eine Ramdisk,
nämlich /run. Ansonsten ist das Einrichten auch nicht schwer, eine Zeile
in /etc/fstab und bei laufendem Betrieb ein mount. Das lässt sich auch
bei der Installation eines Programmes machen.
Für das System ist der Umweg nicht so sehr groß, im Wesentlichen das
Registrieren von Informationen wie Zeitstempel und Dateilänge.
Informationen, die aber für vieles auch brauchbar sind . Die Ramdisk
(ramfs oder tmpfs) ist ja auch recht einfach gegenüber anderen
Dateisystemen.
> Eine Datei hat gegenüber dem shared memory den Vorteil, dass sie viel> einfacher zu handhaben ist und ohne Aufwand kopiert oder eingelesen> werden kann.
Bei shared memory hält sich der Aufwand auch in Grenzen. Letztendlich
braucht man im wesentlichen nur shmget und shmat (und für den daemon
noch shmdt und shmctl, um das Segment beim Beenden zu löschen).
Dafür muss man nicht jedes Mal die Variablen einlesen, sondern hat
direkten Zugriff. Locking habe ich bis jetzt auch immer gleich über
Flag-Variablen im SHM gemacht, weil das meiner Meinung nach am
flexibelsten ist.
Jörg
Joerg W. schrieb:> Locking habe ich bis jetzt auch immer gleich über> Flag-Variablen im SHM gemacht, weil das meiner Meinung nach am> flexibelsten ist.
Wie sorgst du dafür, dass der lesende Prozess die Schreibzugriffe in der
selben Reihenfolge sieht? Wie wartest du darauf dass der Bereich
freigegeben wird, per Spinlock?
Dr. Sommer schrieb:> Wow, jetzt fühl ich mich richtig motiviert was für dich zu> programmieren.
Naja, dann laß' es meinetwegen. Es ist und bleibt eine Tatsache, daß es
für das fachliche Ziel des TO ein fertiges Muster namens
Publish-Subscribe, und vielfach bewährte, gut getestete
Implementierungen dafür gibt, ganz egal ob man nun eine Library (wie
ZeroMQ) benutzt oder eine externe Software. Ob Du Deinen Editor jetzt
anwirfst oder ihn kalt läßt, ändert nichts daran.
Mit ZeroMQ ist die Sache allerdings wirklich ein Kinderspiel. Ein
Publisher könnte so aussehen (Linken mit -lzmq nicht vergessen!):
1
#include<zmq.h>
2
#include<stdio.h>
3
#include<unistd.h>
4
#include<string.h>
5
6
intmain(void){
7
8
void*context=zmq_ctx_new();
9
void*sock=zmq_socket(context,ZMQ_PUB);
10
zmq_bind(sock,"tcp://127.0.0.1:5555");
11
12
charbuf[]="bla Hello World!";
13
14
sleep(1);/* wait for our clients */
15
16
for(inti=0;i<10;++i){
17
zmq_send(sock,buf,strlen(buf),0);
18
}
19
20
zmq_close(sock);
21
zmq_ctx_destroy(context);
22
23
return0;
24
}
und ein Subscriber:
1
#include<zmq.h>
2
#include<stdio.h>
3
4
#define MAXLEN 255
5
6
intmain(void){
7
8
void*context=zmq_ctx_new();
9
void*sock=zmq_socket(context,ZMQ_SUB);
10
zmq_connect(sock,"tcp://localhost:5555");
11
zmq_setsockopt(sock,ZMQ_SUBSCRIBE,"bla",3);
12
13
charbuf[MAXLEN+1];
14
15
while(1){
16
intsize=zmq_recv(sock,buf,MAXLEN,0);
17
buf[size]='\0';
18
printf("%s\n",buf);
19
}
20
21
zmq_close(sock);
22
zmq_ctx_destroy(context);
23
24
return0;
25
}
35 Zeilen Code. Meine Güte, diese Photonentorpedos! ;-)
S. R. schrieb:> Was hindert den TO eigentlich daran, die Daten in die Datei zu> schreiben, statt nur deren Adresse?
Woher wissen die lesenden Prozesse denn dann, daß neue Daten verfügbar
sind? Also ist schon wieder eine Synchronisation notwendig.
Verzeihung, aber Dateien und Ramdisks gibt es unter UNIXoiden schon
ziemlich lange, das ganze System beruht doch auf dem Konzept "alles ist
eine Datei". Aber trotzdem haben die Väter von UNIX recht aufwändige
Mechanismen für die Interprozesskommunikation implementiert. Warum nur?
Vielleicht weil sich mit Dateien eben doch nicht alles abbilden läßt?
Dr. Sommer schrieb:> Sheeva P. schrieb:>> 35 Zeilen Code. Meine Güte, diese Photonentorpedos! ;-)>> Und jetzt bitte noch Kafka und Redis einbinden.
Du willst es nicht verstehen. Auch gut.
Hallo,
also ich hab es zuerst mit Named Pipe ausprobiert, ist aber für meine
zwecke nicht sehr tauglich. Es zieht unmengen an CPUleistung, genau so
gut auf eine Datei zugreiben in diese schreiben und daraus auslesen.
so ab ich es mal mit shared Memory probiert. mein bisheriger Code sieht
wie folgt aus:
1
#include<stdio.h>
2
#include<stdint.h>
3
#include<stdlib.h>
4
#include<sys/shm.h>
5
#include<time.h>
6
7
structshared_memory1_struct
8
{
9
uint16_tshared_data;
10
};
11
12
void*shared_memory1_pointer=(void*)0;
13
//Variablen
14
structshared_memory1_struct*shared_memory1;
15
intshared_memory1_id;
16
intmain(void)
17
{
18
uint8_ti;
19
uint8_ti_sm;//counter für shared memory
20
21
//erstelle Shared Memory
22
printf("erstelle shared memory...\n");
23
shared_memory1_id=shmget((key_t)213151587,sizeof(structshared_memory1_struct),0666|IPC_CREAT);///0666 everyone can read and write
Auslesen lassen wollte ich das mit Python2.7, da es für eines meiner
Bauteile leider nur eine Python Bibiothek gibt...
das hab ich folgendermaßen gemacht:
1
import sysv_ipc
2
import time
3
memory = sysv_ipc.SharedMemory(213151587)
4
memory_value = memory.read()
5
while True:
6
ausgabe = memory_value
7
ausgabe = map(ord,ausgabe)
8
print ausgabe
9
time.sleep(1)
bei zweistelligen zahlen wird die zahl zwar noch richtig ausgegeben,ist
aber nur die erste zahl von einem vector der göße ca. [1x100]. die erste
zahl beispielsweise 20 steht in der ersten spalte, danach folgen
unzählige nullen.
wird eine 4stellige zahl wie oben im code ausgegeben, so erhalte ich:
[229, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0]
wo liegt hier der Fehler ?
Lu schrieb:> also ich hab es zuerst mit Named Pipe ausprobiert, ist aber für meine> zwecke nicht sehr tauglich. Es zieht unmengen an CPUleistung,
Dann hast du etwas falsch gemacht. Wenn du nicht gerade Gigabytes pro
Sekunde an Daten überträgst, ist der Overhead nicht merkbar.
Sheeva P. schrieb:> Verzeihung, aber Dateien und Ramdisks gibt es unter UNIXoiden schon> ziemlich lange, das ganze System beruht doch auf dem Konzept "alles ist> eine Datei". Aber trotzdem haben die Väter von UNIX recht aufwändige> Mechanismen für die Interprozesskommunikation implementiert. Warum nur?> Vielleicht weil sich mit Dateien eben doch nicht alles abbilden läßt?
Hat doch keiner gesagt, dass man shared memory oder andere IPC-Techniken
nicht verwenden sollte. Hingewiesen wurde nur auf die Tatsache, dass man
auch gewöhnliche Dateien verwenden kann.
Beides hat seine Vor- und Nachteile, die je nach Anwendungsfall
bedeutsam sind. Nach den spärlichen Informationen des Themenerstellers
wäre für seinen Fall beides möglich. Über ähnliche Fälle von anderen
Interessenten dieses Themas können wir nichts wissen, also ist es gut,
alle Möglichkeiten aufzuzeigen.
IPC-Techniken sind ein geschlossenes System nur für eingeweihte Prozesse
auf demselben Rechner. Dateien sind ein offenes System,die Daten sind
auch für andere Rechner im Netzwerk zugänglich.
Sheeva P. schrieb:>> Was hindert den TO eigentlich daran, die Daten in die Datei zu>> schreiben, statt nur deren Adresse?>> Woher wissen die lesenden Prozesse denn dann, daß neue Daten verfügbar> sind? Also ist schon wieder eine Synchronisation notwendig.
Nun, die lesenden Prozesse könnten z.B. feststellen, dass die Datei
gewachsen ist, oder dass sich ihr Zeitstempel geändert hat... das
passiert üblicherweise, wenn man neue Daten an eine Datei schreibt.
Aber du missverstehst mich:
Die ursprüngliche Aufgabe bestand aus "Ich schreibe die Adresse eines
Speicherblocks in eine Datei und meine Daten in den Speicher an diese
Adresse. N andere Prozesse sollen nun die Daten an dieser Adresse
vorfinden."
Mir ging es darum, dass man
a) auch die Daten selbst in eine Datei schreiben könnte;
b) diese Datei per mmap() mit MAP_SHARED einbinden könnte.
Genau das gibt dem TO, wonach er gefragt hat.
Shared Memory ebenfalls (und ist besser).
Sheeva P. schrieb:> Verzeihung, aber Dateien und Ramdisks gibt es unter UNIXoiden schon> ziemlich lange, das ganze System beruht doch auf dem Konzept "alles ist> eine Datei".
Und? Es hat sich erstaunlich lange erstaunlich gut bewährt. Deswegen
muss man es nicht wegschmeißen. Ich sehe allerdings ein, dass sich die
Welt weitergedreht hat:
- statt Dateien haben wir Datenbanken;
- statt normaler Daten haben wir Content;
- unsere Daten sind jetzt Big.
Und da die Menschheit inzwischen Zugang zu quasi unbegrenzt Speicher und
Rechenzeit hat (AWS & Co), muss man das natürlich auch ausnutzen. Es gab
mal eine Zeit, da war TCP ein Overhead, den man nicht unnötigerweise
wollte. Aber das war auch vor Javascript und Python...
S. R. schrieb:> Sheeva P. schrieb:>> Woher wissen die lesenden Prozesse denn dann, daß neue Daten verfügbar>> sind? Also ist schon wieder eine Synchronisation notwendig.>> Nun, die lesenden Prozesse könnten z.B. feststellen, dass die Datei> gewachsen ist, oder dass sich ihr Zeitstempel geändert hat... das> passiert üblicherweise, wenn man neue Daten an eine Datei schreibt.
Hm. Wenn ich das richtig verstanden haben, sollte das Ganze unter
Raspbian laufen. Raspbian läuft in der Regel auf SBCs, die wiederum
üblicherweise von SD-Karten laufen. SD-Karten verkraften aber leider nur
eine begrenzte Zahl an Schreibzyklen; das wird zwar durch den
Dateisystempufer teilweise abgefedert, aber früher oder später wird die
SD-Karte kaputt gehen. Darum erscheint es mir für diesen Anwendungsfall
durchaus sinnvoll zu sein, eine Ramdisk zu benutzen -- aber nicht aus
Performancegründen, sondern nur um Schreibzyklen zu sparen und so die
Lebensdauer der SD-Karte zu erhöhen.
Ja, natürlich könnte man auch eine externe USB-Platte benutzen, aber für
den Preis einer externen USB-Disk bekomme ich 8 SD-Karten... naja, YMMV.
Aber kommen wir zu den anderen konzeptionellen Problemen mit Deinen
beiden Ansätzen. Zunächst einmal brauchen beide Ansätze -- sowohl die
Prüfung der Dateigröße als auch die der Zugriffszeiten -- eine
Synchronisierung. Sonst wissen die lesenden Prozesse nämlich entweder
nicht, daß es etwas zu lesen gibt -- oder sie pollen sich an den
Metadaten zu Tode und erzeugen damit eine signifikante Last auf der CPU.
Bei dem Ansatz mit der Dateigröße käme hinzu, daß es ja auch irgendeiner
Art von Housekeeping bedarf, damit das Dateisystem nicht überläuft. Der
Ansatz mit den Zugriffszeiten hingegen erhöht wiederum die Schreiblast
-- das geht damit wieder auf die Lebensdauer der SD-Karte. Natürlich
können beide Ansätze kombiniert werden -- der Writer macht dann
periodisch ein f?truncate(2), was die Reader über die Kombination aus
Dateigröße und Zugriffszeit bemerken und dann entweder nur einen
fread(3) machen oder vorher ein fseek(3). Das Problem mit dem Polling
und der Schreiblast besteht bei diesem Ansatz allerdings trotzdem,
solange Du nicht mit Semaphoren oder Locks arbeiten willst. Wobei Locks
dann wieder ein ganz anderes Schweinchen bieten: wenn der Lockholder
abraucht, ohne das Lock vorher aufgehoben zu haben... ;-)
Bad things happen, all the time.
> Aber du missverstehst mich:>> Die ursprüngliche Aufgabe bestand aus "Ich schreibe die Adresse eines> Speicherblocks in eine Datei und meine Daten in den Speicher an diese> Adresse. N andere Prozesse sollen nun die Daten an dieser Adresse> vorfinden."
Ja, genau so hatte ich das auch verstanden: ein Prozeß schreibt Daten,
und n andere Prozesse sollen sie lesen und verarbeiten. Das ist ein sehr
altes und bekanntes Problem, für das es etliche Lösungen gibt, einige
davon habe ich oben bereits genannt. Für IPv4-Netzwerke wurden für
dieses Problem gar zwei eigene Lösungen entwickelt, Broadcast und
Multicast. Am Ende geht es allerdings um
Punkt-zu-Multipunkt-Kommunikation, und dafür sind Dateien -- die der
Persistierung von Daten und eben nicht zur Kommunikation zwischen
Prozessen dienen -- nun einmal nicht besonders gut geeignet.
> Mir ging es darum, dass man> a) auch die Daten selbst in eine Datei schreiben könnte;> b) diese Datei per mmap() mit MAP_SHARED einbinden könnte.>> Genau das gibt dem TO, wonach er gefragt hat.> Shared Memory ebenfalls (und ist besser).
In beiden Fällen bleibt das Synchronisationsproblem bestehen. Leider hat
sich der TO nicht dazu ausgelassen, wie tolerabel verlorene Writes,
stale Reads oder ggf. sogar Race Conditions für ihn sind.
> Sheeva P. schrieb:>> Verzeihung, aber Dateien und Ramdisks gibt es unter UNIXoiden schon>> ziemlich lange, das ganze System beruht doch auf dem Konzept "alles ist>> eine Datei".>> Und? Es hat sich erstaunlich lange erstaunlich gut bewährt.
... und trotzdem gibt es unter UNIXoiden eine Vielzahl alter und
moderner Konzepte für die Interprozeßkommunikation. Wenn das gute alte
"alles ist eine Datei"- Konzept sich so gut und für alle möglichen
Anwendungsfälle bewährt hätte, würde es die alle nicht geben.
> Deswegen muss man es nicht wegschmeißen.
Aber wer will das denn? Alles, was ich sage, ist: für den Anwendungsfall
des TO gibt es ein fertiges und bewährtes Konzept, welches eben nicht
mit Dateien mit ihren inhärenten Synchronisationsproblemen arbeitet, und
das heißt Publish-Subscribe und steht in etlichen Implementierungen
(sogar verschiedene Datenbanken bieten mit dem Notify-Listen-Modell eine
Lösung für dieses häufige Problem an) stabil und getestet zur Verfügung.
Diese Implementierungen sind nicht nur stabil und getestet, sondern
bereits so umfangreich optimiert, daß niemand hier -- mich
eingeschlossen -- eine adäquate und äquivalente Alternative schreiben
könnte, ohne dafür einen erheblichen Aufwand zu betreiben.
> Ich sehe allerdings ein, dass sich die> Welt weitergedreht hat:> - statt Dateien haben wir Datenbanken;> - statt normaler Daten haben wir Content;> - unsere Daten sind jetzt Big.
Na komm, die Sprüchlein über "Content" und "Big Data" sind Polemik, das
weißt Du genau so gut wie ich. Was hingegen die Datenbanken angeht, so
existieren gute Gründe dafür, ebensolche zu benutzen, denn dabei geht es
schließlich um genau die Probleme, die sich mit einfachen Dateien eben
nicht so einfach lösen lassen. Wie, wenn ich das mal so sagen darf, der
Anwendungsfall des TO -- und der ist ja noch relativ easy, denn bei ihm
gibt es ja nur einen Writer. Wenn das alles so einfach mit Dateien
ginge, dann würde es keine Datenbanken geben, und Larry Ellison wäre ein
armer Schlucker mit einer abgewrackten Jolle. (Nicht, daß ich ihm das
nicht von Herzen gönnen würde... ;-))
> Und da die Menschheit inzwischen Zugang zu quasi unbegrenzt Speicher und> Rechenzeit hat (AWS & Co), muss man das natürlich auch ausnutzen. Es gab> mal eine Zeit, da war TCP ein Overhead, den man nicht unnötigerweise> wollte. Aber das war auch vor Javascript und Python...
Also wenn Du schon ein "o tempora, o mores" anstimmen und Dich
vielleicht auch noch über die Jugend auslassen möchtest, die ja schon
Aristoteles für "unerträglich, unverantwortlich und entsetzlich
anzusehen" hielt, dann sind ausgerechnet Javascript und Python
vermutlich die schlechtesten Beispiele unter den modernen
Skriptsprachen. ;-)
Sheeva P. schrieb:> Wenn ich das richtig verstanden haben, sollte das Ganze unter> Raspbian laufen. Raspbian läuft in der Regel auf SBCs, die> wiederum üblicherweise von SD-Karten laufen.
Darum: Ramdisk.
Sheeva P. schrieb:> Sonst wissen die lesenden Prozesse nämlich entweder> nicht, daß es etwas zu lesen gibt -- oder sie pollen> sich an den Metadaten zu Tode und erzeugen damit eine> signifikante Last auf der CPU.
Der Kernel kann dir mitteilen, wenn etwas geschehen ist (z.B. inotify).
Man muss keine 100% CPU verbraten, um Dateiänderungen mitzubekommen.
Ich kann mir nicht vorstellen, dass du das nicht weißt. Warum behauptest
du also, es wäre nicht sinnvoll möglich?
Im Ursprungsproblem wäre es aber egal, ob ich eine Variable im shm polle
oder ob ich ein Byte in einer ge-mmap()-ten Datei polle. Geschenkt.
Sheeva P. schrieb:> Ja, genau so hatte ich das auch verstanden: ein Prozeß schreibt Daten,> und n andere Prozesse sollen sie lesen und verarbeiten.
Und zwar über eine Adresse im RAM. Dass das rückwirkend garnicht das
Problem ist, sei mal dahingestellt. :-)
Sheeva P. schrieb:> In beiden Fällen bleibt das Synchronisationsproblem bestehen.
Darüber hat der TO kein Wort verloren, also bin ich davon ausgegangen,
dass das Problem entweder gelöst ist oder gelöst wird. Lösungen auf
Dateibasis sind auch möglich (record-based locking o.ä.).
Sheeva P. schrieb:> Wenn das gute alte "alles ist eine Datei"- Konzept> sich so gut und für alle möglichen Anwendungsfälle> bewährt hätte, würde es die alle nicht geben.
Es gibt heutzutage Räder aus verschiedensten Materialien in
verschiedensten Farben, aber das ursprüngliche metallbeschlagene Holzrad
funktioniert heute auch noch - wenn man nicht gerade mit 200 km/h und 2t
Leergewicht über eine verkrebste Betonautobahn brettern will. Und selbst
dann ist das eher eine Frage von der Größe des Rades.
Hier ist das Konzept möglicherweise durchaus sinnvoll einsetzbar, obwohl
es auch andere Konzepte gibt. Was für den TO passt, kann nur der TO
einschätzen, denn was wir über das Problem wissen, ist dürftig.
Was du machst ist missionieren, und das ist genauso nervig wie flamen.
Zumal die Kompetenz in Bezug auf die anderen Lösungen hier deutlich
höher sein dürfte als dein Vorschlag. Bei Leuten, die mit verteilten
Systemen zu tun haben, ist das vermutlich sogar andersrum.
Sheeva P. schrieb:> Na komm, die Sprüchlein über "Content" und "Big Data"> sind Polemik, das weißt Du genau so gut wie ich.
Teilweise, ja. Aber nicht so viel wie du glaubst.
Schau dir mobile Betriebssysteme an: Da kommst du nicht mehr mit Dateien
in Berührung, sie werden aktiv vor dir versteckt. Es gibt nur Content
und ContentProvider, mit denen man "Bilder", "Videos", "Musikstücke",
"Apps" und so weiter benutzt. Auf iGeräten konnte (kann?) man keine
Dateien speichern, die das Gerät nicht versteht.
Das Autoradio meines Vaters kann zwar mit MP3 umgehen, unterstützt aber
keine Dateinamen mehr - die gesamte Benutzerführung läuft über die
Metadaten (und bringt meinen Vater regelmäßig zur Weißglut).
Big Data (bzw. große Datenbanken) ist nur möglich, weil man inzwischen
große, verteilte Systeme halbwegs im Griff hat. Dateien, also an sich
unstrukturierte, lokale Bytehaufen mit festem Ort passen da nicht
rein. Netzwerkdateisysteme sind und waren schon immer eine Krücke.
In der Cloud gibt es keine Orte mehr (soll es auch nicht geben), auch
keine unstrukturierten Daten, nur noch annotierte, durchsuchbare
Inhalte. Die Suchfunktion ersetzt das Menü - schau dir Chrome oder
Android an. Vorschlagsysteme machen die Suchfunktion benutzbarer.
Lernende, sich ständig anpassende Systeme verhindern sogar aktiv das
motorische Gedächtnis.
Auf Serverseite hantiert man zwar noch mit Dateien, aber auch da wird es
weniger (z.B. Docker, diverse Administrationsoberflächen). Eine normale
Android-App besteht aus einer Ordnerstruktur, die ohne IDE kaum
erträglich ist. Make ist dateigetrieben, aktuelle Buildsysteme (CMake,
gradle, pip) sind stattdessen datengetrieben (und holen sich notwendige
Dinge direkt aus dem Netz).
Das ist die aktuelle Entwicklung.
Kann man mögen oder auch nicht, aber weg geht das nicht mehr.
Sheeva P. schrieb:> dann sind ausgerechnet Javascript und Python> vermutlich die schlechtesten Beispiele unter den modernen> Skriptsprachen. ;-)
Sowohl in Javascript als auch in Python (zu nennen wäre definitiv auch
PHP) wird unglaublich viel unglaublich schlechter Code verzapft. Damit
meine ich nicht die Sprachen selbst, sondern ihre Nutzer.
Eine gute Beschreibung, die ich dazu heute gelesen habe, nannte es das
"Visual Basic-Symptom". Die übliche Nutzerbasis von Visual Basic (und
insbesondere VBA) kann nämlich nicht programmieren, sondern bastelt sich
eine Lösung zusammen, die das aktuelle Problem irgendwie löst. Das
Ergebnis (und der resultierende Ruf von Visual Basic) ist bekannt.
S. R. schrieb:> Darum: Ramdisk.
Das schrieb ich ja. Das heißt dann aber leider auch, daß die Ramdisk
eingerichtet werden muß, womit zusätzliche Abhängigkeiten und damit
potentielle Fehlerquellen außerhalb der Software erzeugt werden. Das
kann man machen, aber sonderlich elegant ist das leider nicht.
> Der Kernel kann dir mitteilen, wenn etwas geschehen ist (z.B. inotify).> Man muss keine 100% CPU verbraten, um Dateiänderungen mitzubekommen.>> Ich kann mir nicht vorstellen, dass du das nicht weißt. Warum behauptest> du also, es wäre nicht sinnvoll möglich?
Weil ich schon sehr intensiv mit inotify gearbeitet habe und daher weiß,
daß es in vielen Fällen Writes verliert. Die Manpage von inotify(7)
warnt sogar ausdrücklich davor: "Note that the event queue can overflow.
In this case, events are lost. Robust applications should handle the
possibility of lost events gracefully".
> Im Ursprungsproblem wäre es aber egal, ob ich eine Variable im shm polle> oder ob ich ein Byte in einer ge-mmap()-ten Datei polle. Geschenkt.
Polling ist halt Mist. Immer. Sowas macht ein guter Entwickler nur dann,
wenn es wirklich nicht anders geht.
> Sheeva P. schrieb:>> Ja, genau so hatte ich das auch verstanden: ein Prozeß schreibt Daten,>> und n andere Prozesse sollen sie lesen und verarbeiten.>> Und zwar über eine Adresse im RAM. Dass das rückwirkend garnicht das> Problem ist, sei mal dahingestellt. :-)
Das war die Idee des TO, aber nicht der Anwendungsfall. Ohne
spezielle Techniken wie Shared Memory könnte er ohnehin nicht mit einem
Prozeß auf eine Adresse zugreifen, die einem anderen Prozeß gehört.
Erstens, weil jedes moderne Betriebssystem das mit einer
Zugriffsverletzung quittiert.
Zweitens aber auch deswegen, weil prozessintern gar nicht mit absoluten
Speicheradressen gearbeitet wird, sondern mit relativen. Sogar wenn
unser TO seinen Prozeß dazu bringt, die Speicheradresse einer Variablen
in eine Datei zu schreiben, würde ihm das nichts nutzen: denn die
Speicheradresse 0x123 seines Writer-Prozesses W zeigt natürlich auf
einen völlig anderen physikalischen Speicher als die Speicheradressen
0x123 seiner Reader.
> Darüber hat der TO kein Wort verloren, also bin ich davon ausgegangen,> dass das Problem entweder gelöst ist oder gelöst wird.
Angesichts der Fragestellung des TO, die, wie im vorhergehenden
Abschnitt beschrieben, fundamental mit der Speicherverwaltung seines
Betriebssystem kollidiert, halte ich diese Annahme für, mit Verlaub,
naiv. Im Gegenteil gehe ich eher davon aus, daß sich der TO um
Concurrency, Synchronisation, Lost Writes, Stale Reads, Race Conditions
oder ähnliche Fallstricke noch überhaupt gar keine Gedanken gemacht hat.
;-)
> Lösungen auf Dateibasis sind auch möglich (record-based locking o.ä.).
Also lieber selbst eine Datenbank schreiben, anstatt eine vorhandene zu
benutzen? Hauerha, das wird spannend! ;-)
> Es gibt heutzutage Räder aus verschiedensten Materialien in> verschiedensten Farben, aber das ursprüngliche metallbeschlagene Holzrad> funktioniert heute auch noch - wenn man nicht gerade mit 200 km/h und 2t> Leergewicht über eine verkrebste Betonautobahn brettern will. Und selbst> dann ist das eher eine Frage von der Größe des Rades.
Du wirst es trotzdem nicht erleben, daß ich mit einem metallbeschlagenen
Holzrad an einem Downhill-Rennen teilnehme.
> Hier ist das Konzept möglicherweise durchaus sinnvoll einsetzbar, obwohl> es auch andere Konzepte gibt. Was für den TO passt, kann nur der TO> einschätzen, denn was wir über das Problem wissen, ist dürftig.
Das ist allerdings wahr.
> Was du machst ist missionieren, und das ist genauso nervig wie flamen.
Das magst Du vielleicht so wahrnehmen, ist aber nicht der Fall. Tatsache
ist, daß ich ressourcenschonende und fertige Lösungen für das Problem
des TO angeboten habe, woraufhin mich ein gefühlt besonders kluger
Mensch darauf hingewiesen hat, daß das ja alles viel zu aufwändig und
deswegen "mit Photonentorpedos auf Amöben" geschossen sei. Stattdessen
hat der besagte kluge Mensch etwas vorgeschlagen, das keine Lösung sein
kann, da damit zwar der reine Datenaustausch zwischen den Prozessen
realisiert, das unserer Fragestellung inhärente Synchronisationsproblem
damit aber leider nicht korrekt gelöst werden kann.
> Zumal die Kompetenz in Bezug auf die anderen Lösungen hier deutlich> höher sein dürfte als dein Vorschlag. Bei Leuten, die mit verteilten> Systemen zu tun haben, ist das vermutlich sogar andersrum.
Mag sein, aber ich habe nun einmal mit verteilten Systemen zu tun und
weiß daher, daß es für solche Probleme bereits fertige Lösungen gibt,
die das Gewünschte mit wenigen Zeilen Code (siehe meine Beispiele oben)
zur Verfügung stellen und kein einziges der Probleme haben, über die wir
hier diskutieren. Und die einzigen "traditionellen" UNIX-Lösungen leiden
alle darunter, daß sie wesentlich schwieriger und aufwändiger umzusetzen
sind als die von mir gezeigte Lösung mit ZeroMQ.
Mal schauen, wenn ich Zeit und Lust habe, schreib' ich vielleicht auch
noch ein kleines Beispiel mit Redis. Ja, damit schaffe ich auch
Abhängigkeiten außerhalb der Software, aber dafür bietet Redis noch ein
paar sehr nette Zusatzmöglichkeiten für eine Software, die letzten Endes
nicht nur Daten zwischen verschiedenen Prozessen austauschen, sondern
auch händeln muß.
> Das Autoradio meines Vaters kann zwar mit MP3 umgehen, unterstützt aber> keine Dateinamen mehr - die gesamte Benutzerführung läuft über die> Metadaten (und bringt meinen Vater regelmäßig zur Weißglut).
Das tut mir zwar ausgesprochen leid für Deinen Herrn Papa (bitte grüße
ihn unbekannterweise von mir), ist hier aber nicht das Thema. Soweit ich
weiß, können die in Mediadateien vorhandenen Metadaten aber editiert
werden, so daß es möglicherweise kein Problem wäre, den Dateinamen
einfach in diese Metadatenfelder hinein zu schreiben? Hab' ich aber
nicht ausprobiert.
> Big Data (bzw. große Datenbanken) ist nur möglich, weil man inzwischen> große, verteilte Systeme halbwegs im Griff hat. Dateien, also an sich> unstrukturierte, lokale Bytehaufen mit festem Ort passen da nicht> rein.
Tatsächlich geht "Big Data" heute genau in diese Richtung, in Form eines
sogenannten "Data Lake". Darin sammeln der Betreiber zunächst einmal
alle Daten, derer er habhaft werden kann, strukturierte und
unstrukturierte, alles idealerweise im Rohformat. Erst bei der
Exploration und Analyse der Daten werden diese je nach Bedarf ausgewählt
und (meist) in strukturierte Daten überführt.
Wie dem auch sei, dieses Thema können wir gerne ein andermal und in
einem anderen Thread besprechen, aber hier gehört das nicht her.
Sheeva P. schrieb:> Das war die Idee des TO, aber nicht der Anwendungsfall.
Ich gehöre zu den Menschen, die anderen gerne bei der Lösung ihrer
Probleme helfen - und wenn mich jemand direkt nach X fragt, dann bekommt
er auch eine Antwort zu X. Manchmal auch dann, wenn er eigentlich Y
meinte. :-)
Sheeva P. schrieb:> Wie dem auch sei, dieses Thema können wir gerne ein andermal und in> einem anderen Thread besprechen, aber hier gehört das nicht her.
Da hast du wohl recht. Gute Nacht. :-)
S. R. schrieb:> Ich gehöre zu den Menschen, die anderen gerne bei der Lösung ihrer> Probleme helfen - und wenn mich jemand direkt nach X fragt, dann bekommt> er auch eine Antwort zu X. Manchmal auch dann, wenn er eigentlich Y> meinte. :-)
Die korrekte Antwort auf das "X" des TO wäre das gewesen, was ich in
meinem vorherigen Beitrag in den beiden mit "Das war die Idee des TO"
beginnenden Abschnitten geschrieben habe. Mir ging es nur darum, dem TO
auch das "Y" zu zeigen, also: wie er sein eigentliches Problem sauber
lösen kann.
> Sheeva P. schrieb:>> Wie dem auch sei, dieses Thema können wir gerne ein andermal und in>> einem anderen Thread besprechen, aber hier gehört das nicht her.>> Da hast du wohl recht. Gute Nacht. :-)
Dankeschön, Dir auch. ;-D
Spaßeshalber habe ich die PubSub-Lösung jetzt auch noch einmal mit Redis
implementiert. Das Error-Handling ist sicherlich noch
verbesserungswürdig, aber das Prinzip wird hoffentlich klar.
Publisher: