Forum: PC-Programmierung shared mamory: Blockweise schreiben bzw. lesen


von Hans (Gast)


Lesenswert?

Hallo,


ich programmiere unter Linux C#. Ich bin an einem problem angekommen wo 
ich einfach nicht weiterkomme.


Ich lese mit read () und rbuffer34, aus einen Device die Anzahl 
BytesToRead aus.


  hDevice = open("/dev/ics554-1", O_RDWR);
  ULONGLONG        *rbuffer34[10];

    if (0 > read (hDevice, rbuffer34[x], BytesToRead)) {
       perror("read34[0]");
    }


anschliessend wollte ich diese Daten, also die kompletten BytesToRead, 
in ein Shared Mamory Blockweise schreiben und mit printf(..) einen int 
wert auf den terminal ausgeben lassen(um zu gucken ob bzw. was dort 
steht).
Man könnte zwar sofort, die BytesToRead, in eine Datei schreiben, das 
wollte ich allerdings mit einem anderen Prozess machen und die Daten 
vorher im Shared Mamory puffern.

   int *shPtr2I, WriteBytes;

   shID2I = shmget(IPC_PRIVATE, MAXMYMEM, IPC_CREAT|0666);
   shPtr2I = shmat(shID2I, 0, 0);

   WriteBytes = write(*shPtr2I, rbuffer34[x], BytesToRead);
   printf("WriteBytes = d%, *shPtr2I = %d \n\r",WriteBytes,*shPtr2I );

Für WriteBytes kriege ich eine Zahl raus die BytesToRead entspricht, was 
richtig ist, allesdings kriege ich im terminal für *shPtr2I immer eine 
Null = 0; geprintet. Ich weiss nicht was ich falsch mache, printe ich 
Falsch oder klappt das so nicht mit dem write() bzw read() wie ich es 
mir vorstelle?? jemand eine Idee?

mfg

Hans

von Peter II (Gast)


Lesenswert?

Hans schrieb:
> ich programmiere unter Linux C#

da glaube ich nicht. Es sieht mir mehr wie C aus.

von Hans (Gast)


Lesenswert?

Peter II schrieb:
> da glaube ich nicht. Es sieht mir mehr wie C aus.

das ist auch c aber ich benutze kein windows sondern Linux bzw. Suse 11. 
;-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

>    WriteBytes = write(*shPtr2I, rbuffer34[x], BytesToRead);

Bist Du Dir sicher, daß Du hier den Pointer shPtr2I dereferenzieren 
möchtest?

Übrigens: Es heißt M_e_mory.

von Olaf H. (agentp)


Lesenswert?

Hey!
Ist schon Jahre her, das ich shared mems benutzt habe. Aber ich stelle 
mal ein paar Fragen zum Nachdenken.

Wieso "write" auf nem SHM? Um ins SHM zu schreiben "memcpy" und deren 
Derivate. Um aus einer Datei zu lesen und direkt ins SHM zu schreiben 
"read" nehmen.
1
ULONGLONG        *rbuffer34[10];

ist nicht schön, wenn ich Bytes lesen und schreiben will. Besser UCHAR 
nehmen und die echte Anzahl Bytes allokieren (malloc etc).
1
    if (0 > read (hDevice, rbuffer34[x], BytesToRead)) {
2
      perror("read34[0]");
3
    }

Nochmal den Rückgabewert von "read" prüfen. Ist der -1 im Fehlerfall?
1
   printf("WriteBytes = d%, *shPtr2I = %d \n\r",WriteBytes,*shPtr2I );

Du druckst den Wert des ersten Bytes im SHM aus. Ist das was Du willst 
oder willst Du den WErt des Pointers ausgeben?

Agentp

von Hans (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Übrigens: Es heißt M_e_mory.

Danke für den Tipp.

Olaf H. schrieb:
> Wieso "write" auf nem SHM?

Weil ich auf eine andere Lösung nicht gekommen bin(fehlt einwenig die 
Erfahrung). Ist memcpy schneller als read? oder nur einfacher zu 
handhaben muss die daten so schnell wie möglich schaufeln, desshalb 
wollte ich das blockweise machen. Kenn mich noch nicht mit dem schaufeln 
so aus ;-).

Olaf H. schrieb:
> Besser UCHAR
> nehmen und die echte Anzahl Bytes allokieren (malloc etc).

Es ist so, dass eigenlich mit 64 bit Werten gearbeitet wird. Später 
werden die 64bit in zwei 32 bit Werte auseinander gepflückt.
Die Daten liegen im hDevice Binär vor. Es wird auch alloiert wie das 
aussieht im DMA Speicher: (Sorry aber ich habe den C-Code nicht komplett 
geschrieben, muss mich erst durchkämpfen)

rbuffer34[i] = (ULONGLONG *) ics554AllocateDmaBuffer 
(hDevice,BytesToRead);
      if (NULL == rbuffer34[i]) {
        printf ("\nCouldn't allocate memory or insufficient memory.\n");
        goto ErrorExit;
      }
      memset (rbuffer34[i], 0, BytesToRead);
    }


Olaf H. schrieb:
> Nochmal den Rückgabewert von "read" prüfen.

Der Rückgabewert von read entspricht BytesToRead, es wurde also richtig 
gelesen.

Olaf H. schrieb:
> Du druckst den Wert des ersten Bytes im SHM aus

Ja das ist was ich will, nur habe ich gedacht, das ich nicht das erste 
byte ausdrucke sondern die ersten 4byte(da ein 64bit system und 
printf(%d) bzw. int *shPtr2I).

von Olaf H. (agentp)


Lesenswert?

Hans schrieb:
>
> Olaf H. schrieb:
>> Nochmal den Rückgabewert von "read" prüfen.
>
> Der Rückgabewert von read entspricht BytesToRead, es wurde also richtig
> gelesen.
OK
>
> Olaf H. schrieb:
>> Du druckst den Wert des ersten Bytes im SHM aus
>
> Ja das ist was ich will, nur habe ich gedacht, das ich nicht das erste
> byte ausdrucke sondern die ersten 4byte(da ein 64bit system und
> printf(%d) bzw. int *shPtr2I).

OK. Du druckst auch nicht das erste Byte aus. Die Typen müssen auch beim 
printf stimmen. Wenn Du 32 oder 64-bittige Werte ausdruckst unbedingt 
die man-page von printf konsultieren. Da müsste noch eine Option an das 
"d" angehängt werden. Bei "int" ist das nicht notwendig. Ich glaube ja 
Du schreibst keine oder nicht die richtigen WErte ins SHM, weil Du 
"write" benutzt. "memcpy" ist glaube ich "oldstyle" und ich bin nicht 
sicher ob das durch "write" ersetzt wird, weil "write" eigentliche eine 
Funktion im Zusammenhang mit Files ist. Daher nochmal manpage von 
"write" lesen. Wenn Du nichts ins SHM schreibst bekommst du evtl. immer 
Nullen ausgelesen, weil der Speicher beim anlegn genullt wurde.

von Hans (Gast)


Lesenswert?

und da ich mit Files arbeite, ist doch write dann die richtige wahl 
oder?

die syntax von read/write sieht wie folgt aus:


int read(int fh, const void *puffer, site_t bytezahl);
int write(int fh, const void *puffer, size_t bytezahl);


Demnach ist doch meine Verwendung von read/write richtig? oder sehe ich 
den Fehler einfach nicht????

zuerst lesen und in puffer(rbuffer34[x]) ablegen.

  hDevice = open("/dev/ics554-1", O_RDWR);
  ULONGLONG        *rbuffer34[10];
  int *shPtr2I, WriteBytes;

  shID2I = shmget(IPC_PRIVATE, MAXMYMEM, IPC_CREAT|0666);
  shPtr2I = shmat(shID2I, 0, 0);


    if (0 > read (hDevice, rbuffer34[x], BytesToRead)) {
       perror("read34[0]");
    }

Dann ins Shared Memory schreiben:

   WriteBytes = write(*shPtr2I, rbuffer34[x], BytesToRead);
   printf("WriteBytes = d%, *shPtr2I = %d \n\r",WriteBytes,*shPtr2I );


keine Ahnung wie ich jetzt überprüfen soll was in rbuffer[x] jetzt 
steht??

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

>    WriteBytes = write(*shPtr2I, rbuffer34[x], BytesToRead);

Ist "shPtr2I" ein Dateihandle?

Was gibt shmat zurück?

Lies Dir nochmal ganz genau die Dokumentation von shmat durch.

Und überleg mal, warum das ganze shared memory und nicht shared file 
heißt.

von Hans (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Ist "shPtr2I" ein Dateihandle?

Nein es ist kein handle sondern ein (int *shPtr2I;).
Habs jetzt auf

   FILE *shPtr2I;

   WriteBytes = write(shPtr2I, rbuffer34[x], BytesToRead);
   printf("WriteBytes = d%, *shPtr2I = %d \n\r",WriteBytes,*shPtr2I );

geändert.

Rufus Τ. Firefly schrieb:
> Was gibt shmat zurück?

shmat gibt die Adresse zurück und mit shPtr2I = shmat(shID2I, 0, 0); 
zeigen wir darauf.

Rufus Τ. Firefly schrieb:
> Und überleg mal, warum das ganze shared memory und nicht shared file
> heißt.

Ich wollte mehrere Binäre Blöcke dort ablegen und mit einem anderen 
prozess verabeiten bzw. formatiert auf die Festplatte schreiben. Da auf 
die Festplatte schreiben länger dauert als ins RAM/Shared memory, wollte 
ich die Blöcke in einem Ringpuffer im SHM anlegen. Bis jetzt habe ich 
gedacht, dass gerade für sowas ein shared memory gut ist??? kann man 
etwa nicht blockweise ins shared memory schreiben?

von Peter II (Gast)


Lesenswert?

Hans schrieb:
> Ich wollte mehrere Binäre Blöcke dort ablegen und mit einem anderen
> prozess verabeiten bzw. formatiert auf die Festplatte schreiben. Da auf
> die Festplatte schreiben länger dauert als ins RAM/Shared memory, wollte
> ich die Blöcke in einem Ringpuffer im SHM anlegen.

sotwas würde ich mit threads machen, es gibt ein schreibethread und eine 
liste von Zeiger incl Größe wo steht was alles rauszuschreiben ist. Wenn 
es rausgeschrieben ist, wird er speicher freigeben.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Hans schrieb:
> das ist auch c aber ich benutze kein windows sondern Linux bzw. Suse 11.

Ich habe da ein kleines Verständnisproblem. Wieso bezeichnet man 
heutzutage "C unter Linux" als "C#"? Habe ich da irgendetwas verpasst? 
Oder geht es hier in Wirklichkeit um eine Anwendung unter Mono?

von Hans (Gast)


Lesenswert?

Peter II schrieb:
> sotwas würde ich mit threads machen, es gibt ein schreibethread und eine
> liste von Zeiger incl Größe wo steht was alles rauszuschreiben ist.

ob thread oder eigener prozess, die Daten müssen doch irgendwo gepuffert 
werden?? z.B. in einem Shared Memory, denn die Zeiger müssen doch 
irgendwohin zeigen? Oder vertue ich mich da??

von Peter II (Gast)


Lesenswert?

Hans schrieb:
> ob thread oder eigener prozess, die Daten müssen doch irgendwo gepuffert
> werden??

bei thread braucht man aber kein shared memory sonder kann den ganz 
normale speicher nutzen sie wie man es ständig bei C macht.

von Hans (Gast)


Lesenswert?

Rufus bist du noch da??

Rufus Τ. Firefly schrieb:
> Ist "shPtr2I" ein Dateihandle?

Nein es ist kein handle sondern ein (int *shPtr2I;).
Habs jetzt auf

   FILE *shPtr2I;

   WriteBytes = write(shPtr2I, rbuffer34[x], BytesToRead);
   printf("WriteBytes = d%, *shPtr2I = %d \n\r",WriteBytes,*shPtr2I );

geändert.

Rufus Τ. Firefly schrieb:
> Was gibt shmat zurück?

shmat gibt die Adresse zurück und mit shPtr2I = shmat(shID2I, 0, 0);
zeigen wir darauf.

Rufus Τ. Firefly schrieb:
> Und überleg mal, warum das ganze shared memory und nicht shared file
> heißt.

Ich wollte mehrere Binäre Blöcke dort ablegen und mit einem anderen
prozess verabeiten bzw. formatiert auf die Festplatte schreiben. Da auf
die Festplatte schreiben länger dauert als ins RAM/Shared memory, wollte
ich die Blöcke in einem Ringpuffer im SHM anlegen. Bis jetzt habe ich
gedacht, dass gerade für sowas ein shared memory gut ist??? kann man
etwa nicht blockweise ins shared memory schreiben?

von Peter II (Gast)


Lesenswert?

warum willst du es immer noch mit shared memory machen? das ist doch der 
falsche ansatz für dein Problem!

Du handelst dir damit mehr Probeme ein als du löst. Du muss dafür eine 
Komplette IPC machen damit sich die beiden Prozesse nicht in die quere 
kommen. Wenn du 2 Prozesse hast muss du dich auch um das Starten und 
beenden kömmen ( wer startet zu erst und was soll passieren wenn sich 
einer unerwartet beendet?).
Wie übergibt du die Parameter für den den beiden Prozessen z.b. in 
welche Datei soll geschrieben werden usw.

Mach es mit threads das sollte für den zweck das richtige sein.

von Olaf H. (agentp)


Lesenswert?

Also "write" ist immer noch falsch. Du hast in die falsche Ríchtung 
geändert. Der Pointer darf kein FH sein.
- Entweder kopierst Du beim Lesen aus dem Gerät die Daten direkt ins SHM 
(mittels "read") oder kopier sie aus dem Zwischenspeicher mittels 
"memcpy" nachdem sie mittels "read" gelesen wurden.
- Der Pointer auf das SHM darf natürlich kein Dateihandle sein. SHM 
haben immer einen Pointer auf die Anfangsadresse des Speicherbereichs. 
Keinen FH.
- Wenn Du "write" benutzt beteutet das, das Daten auf ein "Gerät" mit 
Filehandle geschrieben werden. SHM hat kein FH (jedenfalls 
normalerweise)

AgentP

von Hans (Gast)


Lesenswert?

Peter II schrieb:
> warum willst du es immer noch mit shared memory machen?

Ich habe mir es so gedacht, dass ich die Id des angelegten Shm in eine 
Datei schreibe, auf diese Datei und somit auf das shm, können dann zich 
Prozesse zugreifen und die binären Daten dann verarbeiten.

Die IPC habe ich bereits hin gekriegt. Es ist so, dass ich in den SHM 
momentan formatiert befülle(shPtr2I[laufshm] = 
(int)(buffer[jdx*16+j*8+1] & 0xFFFFFF00);) und mit nem anderen Prozess 
die Daten abhole alles kein Problem, weil die formatierte
Beschreibung etwas rechenintensiv ist,wollte ich die Daten binär ins shm 
schreiben und später mit nem zweiten Prozess verarbeiten(ja das stimmt 
das könnte ich auch mit nem thread tun, aber wenn es schon so läuft). 
Werd auf jedenfall mich mal mit den threads auseinandersetzen. Hast du 
einpar tipps für mich? wo soll ich anfangen? Danke trotzdem.

Olaf H. schrieb:
> - Entweder kopierst Du beim Lesen aus dem Gerät die Daten direkt ins SHM
> (mittels "read") oder kopier sie aus dem Zwischenspeicher mittels
> "memcpy" nachdem sie mittels "read" gelesen wurden.


Werd es sofort mal testen, beides!! Danke

von Tobi (Gast)


Lesenswert?

Moin,

nur so als Anregung. In meinem aktuellen Projekt verwende ich 
Messagequeues. Ein Prozess sendet die Daten msgsnd() und der andere 
empfängt sie per msgrcv().

von Hans (Gast)


Lesenswert?

Ich muss gestehen mit memcpy() klappt es wunderbar.

Es hat sich jedoch ein neues Problem aufgetan.
Wenn ich die Daten durch ein sherad Memory hin und her schiebe, müsste 
es nicht so sein, dass die Startadresse des SHM bei beiden Prozessen die 
selbe sein müsste?

Ich printe die Startadresse, in beiden Prozessen, mit(2 SHM`s):

printf("shPtr1I = %u,shPtr2I = %u \n\r \n\r" shPtr1I, shPtr2I);

und die Unterscheiden sich.

Kann das sein das ich beim attach eine Startadresse angeben muss, ich 
attache so?

Prozess main (1) // Erzeuger

shID1I = shmget(IPC_PRIVATE, MAXMYMEM, IPC_CREAT|0666);
shPtr1I = shmat(shID1I, 0, 0);
SHMStartPtr12 = shmat(shID1I, 0, 0);
shPtrCtrlFile[1] = shPtr1I;

shID2I = shmget(IPC_PRIVATE, MAXMYMEM, IPC_CREAT|0666);
shPtr2I = shmat(shID2I, 0, 0);
SHMStartPtr34 = shmat(shID2I, 0, 0);
shPtrCtrlFile[2] = shPtr2I;


Prozess 2:

 shPtr1I = shmat(SHMidBuffer[0], 0, SHM_RDONLY);
 ShPtrStart1 = shmat(SHMidBuffer[0], 0, SHM_RDONLY);

 shPtr2I = shmat(SHMidBuffer[2], 0, SHM_RDONLY);
 ShPtrStart2 = shmat(SHMidBuffer[2], 0, SHM_RDONLY);

die SHMid stimmt überein. Ich vermute, dass es die Richtigen SHM`s sind 
nur nicht die Startadresse. Die Startadresse benötige ich da der SHM wie 
ein Ringpuffer aufgebaut ist.

hat einer Tipps wegen der Startadresse??

danke

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Hans schrieb:
> Es hat sich jedoch ein neues Problem aufgetan.
> Wenn ich die Daten durch ein sherad Memory hin und her schiebe, müsste
> es nicht so sein, dass die Startadresse des SHM bei beiden Prozessen die
> selbe sein müsste?

Nö, wieso sollte das so sein? Da ist eine MMU involviert, und damit kann 
der Speicher, der natürlich nur eine physikalische Adresse hat, an 
beliebige Adressen im Adressraum der Prozesse gemappt werden.

Hans schrieb:
> Die Startadresse benötige ich da der SHM wie
> ein Ringpuffer aufgebaut ist.

Keine Pointer im Shared Memory verwenden, sondern Offsets relativ zu 
dessen Startadresse. Und schon stört die unterschiedliche Startadresse 
nicht mehr.

von Peter II (Gast)


Lesenswert?

Hans schrieb:
> die SHMid stimmt überein. Ich vermute, dass es die Richtigen SHM`s sind
> nur nicht die Startadresse. Die Startadresse benötige ich da der SHM wie
> ein Ringpuffer aufgebaut ist.

das sind genau die Probleme die man bei Thread nicht hat.

von Hans (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Keine Pointer im Shared Memory verwenden, sondern Offsets relativ zu
> dessen Startadresse


Wenn man den shm-Bereich:

 shPtr1I = shmat(SHMidBuffer[0], 0, SHM_RDONLY);

gibt doch shmat() eine Adresse zurück. Allerdings weiss ich nicht wo 
diese im shm liegt. oder ist das die Startadresse? Wenn man jetzt wüsste 
wo diese liegt, könnte man ja einen offset erzeugen, relativ zur 
startadresse.
Wie findet man das herraus?? wenn beide Prozesse eine andere 
Adressierung verwenden bzw. wie auf den shm zugreifen wenn nicht über 
int *shPtr1I;??


danke

von Nico S. (nico22)


Lesenswert?

Das ist die Startadresse.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Die von shmat zurückgegebene Adresse ist die Startadresse im 
Adressraum des aufrufenden Prozesses, an der der "shared memory"-Block 
eingeblendet wird.

Angenommen, Dein "shared memory"-Block ist 8 kiB groß, und shmat gibt 
die Adresse 0x12340000 zurück, dann belegt der Block die Adressen von

0x12340000 bis 0x12341fff

Wenn in Deinem anderen Prozess der Block beispielsweise an die Adresse 
0x76540000 gemappt wird, belegt er dort folglich die Adressen von

0x76540000 bis 0x76541fff

Wo liegt jetzt Dein Verständnisproblem?

von Hans (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Wo liegt jetzt Dein Verständnisproblem?

Danke ich habe kein verständnisproblem. Hast mir alles beantwortet ich 
war mir nur unsicher ob ich würklich auf mit shmat() auf die 
startadresse gucke oder nicht.

Mich hat durcheinander gebracht:

void *shmat(int shmid, const void *shmaddr, int shmflg);


Zitat: Der Parameter shmid ist die von shmget() ermittelte ID. An den 
Parameter shmaddr kann eine 0 übergegeben werden, dann sucht sich das 
System eine passende Stelle.

passende Stelle ????

Rufus Τ. Firefly schrieb:
> Angenommen, Dein "shared memory"-Block ist 8 kiB groß, und shmat gibt
> die Adresse 0x12340000 zurück, dann belegt der Block die Adressen von
>
> 0x12340000 bis 0x12341fff

Bei diesem Beispiel beinhaltet eine Adresse 1Byte. Ist das immer so??



in meinem Bsp. ist shPtr1I ein int *(int *shPtr1I) ich lese den shm mit 
fwrite(shPtr1I, 1, BytesToRead, fdBin12); blöcke aus und inkrementiere 
die Adresse dann mit shPtr1I += BytesToRead/sizeof(*shPtr1I);
demnach würde sich doch der speicherbereich um 
BytesToRead/sizeof(*shPtr1I) verändern. Ist korreckt so??

sorry für die, für manche leichten fragen aber ich bin noch nicht so 
lange dabei und ich würde gerne alles genau wissen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Hans schrieb:
> Bei diesem Beispiel beinhaltet eine Adresse 1Byte. Ist das immer so??

Auf den üblichen Geräten, mit denen man so hantiert, ja.

Hans schrieb:
> ich lese den shm mit
> fwrite(shPtr1I, 1, BytesToRead, fdBin12); blöcke aus

Nein. Damit liest Du den shared memory NICHT aus. Das ist an der 
Stelle vollkommener Unfug. fwrite hat da GARNICHTS verloren.

von Hans (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Auf den üblichen Geräten, mit denen man so hantiert, ja.

Ich habe ein 64bit system (Suse). Die adressen sind dann doppelt so 
gross wie bei 32bit system, ist das der Unterschied??

Rufus Τ. Firefly schrieb:
> Nein. Damit liest Du den shared memory NICHT aus. Das ist an der
> Stelle vollkommener Unfug. fwrite hat da GARNICHTS verloren.

Sorry hab mich Falsch ausgedrück. Mit fwrite(shPtr1I, 1, BytesToRead, 
fdBin12); schreibe(kopiere) ich was im shm steht, in das File wo ich mit 
dem Filedescriptor (FILE fdBin12) hinzeige. RICHTIG?

von Blinker (Gast)


Lesenswert?

Example two processes comunicating via shared memory: shm_server.c, 
shm_client.c

http://www.cs.cf.ac.uk/Dave/C/node27.html

HTH! :)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Hans schrieb:
> Ich habe ein 64bit system (Suse). Die adressen sind dann doppelt so
> gross wie bei 32bit system, ist das der Unterschied??

Auch diese Adressen adressieren Bytes.

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.