shared mamory: Blockweise schreiben bzw. lesen

Gast #2106971
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
#2107025
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
Gast #2107073
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).
#2107105
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.
Gast #2107248
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??
Gast #2107296
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?
Gast #2107303
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.
Gast #2107354
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??
Gast #2107461
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?
Gast #2107472
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.
#2107478
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
Gast #2108551
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
Gast #2122339
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
Persönliche Seite #2122367
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.
Gast #2123476
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
Persönliche Seite #2123490
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?
Gast #2123571
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.
Persönliche Seite #2123597
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.
Gast #2123731
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?

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