Ich habe ein kleines Problem mit einem meiner Projekte.
Ich habe versucht, ein gut dokumentiertes Beispiel für die Verwendung von Shared Memory mit zu finden fork() aber ohne erfolg.
Grundsätzlich ist das Szenario, dass wenn der Benutzer das Programm startet, ich zwei Werte im gemeinsamen Speicher speichern muss: aktueller_Pfad die ein verkohlen* und ein Dateiname was auch ist verkohlen*.
Abhängig von den Befehlsargumenten wird ein neuer Prozess gestartet fork() und dieser Prozess muss die lesen und ändern aktueller_Pfad Variable im gemeinsamen Speicher gespeichert, während die Dateiname Variable ist nur lesbar.
Gibt es ein gutes Tutorial zu Shared Memory mit Beispielcode (falls möglich), auf das Sie mich verweisen können?
Sie können erwägen, Threads anstelle von Prozessen zu verwenden. Dann wird der gesamte Speicher ohne weitere Tricks geteilt.
– Elomage
4. Februar 2014 um 12:22 Uhr
Die folgenden Antworten behandeln sowohl den System V IPC-Mechanismus, shmget() et al. und auch das reine mmap() Ansatz mit MAP_ANON (aka MAP_ANONYMOUS) – obwohl MAP_ANON wird nicht von POSIX definiert. Es gibt auch POSIX shm_open() und shm_close() zur Verwaltung von Shared-Memory-Objekten. […continued…]
– Jonathan Leffler
15. März 2020 um 3:59 Uhr
[…continuation…] Diese haben den gleichen Vorteil wie der gemeinsam genutzte IPC-Speicher von System V – das gemeinsam genutzte Speicherobjekt kann über die Lebensdauer des Prozesses hinaus bestehen bleiben, der es erstellt (bis ein Prozess ausgeführt wird shm_unlink()), während Mechanismen mit mmap() erfordern eine Datei und MAP_SHARED um die Daten zu speichern (und MAP_ANON verhindert Persistenz). Es gibt ein vollständiges Beispiel im Begründungsabschnitt der Spezifikation von shm_open().
– Jonathan Leffler
15. März 2020 um 4:01 Uhr
sležica
Es gibt zwei Ansätze: shmget und mmap. ich werde reden über mmapda es moderner und flexibler ist, aber Sie können es sich ansehen man shmget (oder diese Anleitung), wenn Sie lieber die Tools im alten Stil verwenden möchten.
Das mmap() Die Funktion kann verwendet werden, um Speicherpuffer mit hochgradig anpassbaren Parametern zuzuweisen, um Zugriff und Berechtigungen zu steuern und sie bei Bedarf mit Dateisystemspeicher zu sichern.
Die folgende Funktion erstellt einen In-Memory-Puffer, den ein Prozess mit seinen Kindern teilen kann:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
void* create_shared_memory(size_t size) {
// Our memory buffer will be readable and writable:
int protection = PROT_READ | PROT_WRITE;
// The buffer will be shared (meaning other processes can access it), but
// anonymous (meaning third-party processes cannot obtain an address for it),
// so only this process and its children will be able to use it:
int visibility = MAP_SHARED | MAP_ANONYMOUS;
// The remaining parameters to `mmap()` are not important for this use case,
// but the manpage for `mmap` explains their purpose.
return mmap(NULL, size, protection, visibility, -1, 0);
}
Das Folgende ist ein Beispielprogramm, das die oben definierte Funktion verwendet, um einen Puffer zuzuweisen. Der übergeordnete Prozess schreibt eine Nachricht, verzweigt sich und wartet dann darauf, dass sein untergeordneter Prozess den Puffer ändert. Beide Prozesse können den gemeinsamen Speicher lesen und schreiben.
#include <string.h>
#include <unistd.h>
int main() {
char parent_message[] = "hello"; // parent process will write this message
char child_message[] = "goodbye"; // child process will then write this one
void* shmem = create_shared_memory(128);
memcpy(shmem, parent_message, sizeof(parent_message));
int pid = fork();
if (pid == 0) {
printf("Child read: %s\n", shmem);
memcpy(shmem, child_message, sizeof(child_message));
printf("Child wrote: %s\n", shmem);
} else {
printf("Parent read: %s\n", shmem);
sleep(1);
printf("After 1s, parent read: %s\n", shmem);
}
}
Aus diesem Grund ist Linux für unerfahrene Entwickler so frustrierend. Die Manpage erklärt nicht, wie man es tatsächlich verwendet, und es gibt keinen Beispielcode. 🙁
– Piepser
13. April 2011 um 22:46 Uhr
Haha, ich weiß, was du meinst, aber eigentlich liegt es daran, dass wir es nicht gewohnt sind, Manpages zu lesen. Als ich lernte, sie zu lesen und mich an sie gewöhnte, wurden sie sogar noch nützlicher als lausige Tutorials mit besonderen Demonstrationen. Ich erinnere mich, dass ich in meinem Betriebssystemkurs eine 10/10 bekommen habe, wobei ich während der Prüfung nur Manpages als Referenz verwendet habe.
– sležica
13. April 2011 um 22:51 Uhr
shmget ist ein wirklich altmodischer, und manche würden sagen, veralteter Weg, Shared Memory zu machen … Besser zu verwenden mmap und shm_openeinfache Dateien oder einfach MAP_ANONYMOUS.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
13. April 2011 um 23:29 Uhr
@Mark @R Ihr habt Recht, ich werde in der Antwort darauf hinweisen, um später darauf zurückgreifen zu können.
– sležica
14. April 2011 um 21:16 Uhr
Nun, diese Antwort wurde aus irgendeinem Grund populär, also habe ich beschlossen, sie lesenswert zu machen. Es hat nur 4 Jahre gedauert
– sležica
26. Mai 2017 um 20:16 Uhr
Mayank
Hier ist ein Beispiel für Shared Memory:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SHM_SIZE 1024 /* make it a 1K shared memory segment */
int main(int argc, char *argv[])
{
key_t key;
int shmid;
char *data;
int mode;
if (argc > 2) {
fprintf(stderr, "usage: shmdemo [data_to_write]\n");
exit(1);
}
/* make the key: */
if ((key = ftok("hello.txt", 'R')) == -1) /*Here the file must exist */
{
perror("ftok");
exit(1);
}
/* create the segment: */
if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) {
perror("shmget");
exit(1);
}
/* attach to the segment to get a pointer to it: */
if ((data = shmat(shmid, NULL, 0)) == (void *)-1) {
perror("shmat");
exit(1);
}
/* read or modify the segment, based on the command line: */
if (argc == 2) {
printf("writing to segment: \"%s\"\n", argv[1]);
strncpy(data, argv[1], SHM_SIZE);
} else
printf("segment contains: \"%s\"\n", data);
/* detach from the segment: */
if (shmdt(data) == -1) {
perror("shmdt");
exit(1);
}
return 0;
}
Schritte :
Verwenden Sie ftok, um einen Pfadnamen und eine Projektkennung in einen System V IPC-Schlüssel zu konvertieren
Verwenden Sie shmget, das ein gemeinsames Speichersegment zuweist
Verwenden Sie shmat, um das von shmid identifizierte gemeinsame Speichersegment an den Adressraum des aufrufenden Prozesses anzuhängen
Führen Sie die Operationen im Speicherbereich durch
Trennen Sie mit shmdt
Warum werfen Sie 0 in eine Leere*, anstatt NULL zu verwenden?
– Clément Péau
28. März 2017 um 15:45 Uhr
Dieser Code verarbeitet jedoch nicht das Löschen des gemeinsam genutzten Speichers. Nachdem das Programm beendet wurde, muss es manuell über ipcrm -m 0 gelöscht werden.
– Bumm
16. September 2019 um 7:15 Uhr
Bharat
Diese sind für die Verwendung von Shared Memory enthalten
#include<sys/ipc.h>
#include<sys/shm.h>
int shmid;
int shmkey = 12222;//u can choose it as your choice
int main()
{
//now your main starting
shmid = shmget(shmkey,1024,IPC_CREAT);
// 1024 = your preferred size for share memory
// IPC_CREAT its a flag to create shared memory
//now attach a memory to this share memory
char *shmpointer = shmat(shmid,NULL);
//do your work with the shared memory
//read -write will be done with the *shmppointer
//after your work is done deattach the pointer
shmdt(&shmpointer, NULL);
#include <stdio.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main ()
{
int segment_id;
char* shared_memory;
struct shmid_ds shmbuffer;
int segment_size;
const int shared_segment_size = 0x6400;
/* Allocate a shared memory segment. */
segment_id = shmget (IPC_PRIVATE, shared_segment_size,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
/* Attach the shared memory segment. */
shared_memory = (char*) shmat (segment_id, 0, 0);
printf ("shared memory attached at address %p\n", shared_memory);
/* Determine the segment's size. */
shmctl (segment_id, IPC_STAT, &shmbuffer);
segment_size = shmbuffer.shm_segsz;
printf ("segment size: %d\n", segment_size);
/* Write a string to the shared memory segment. */
sprintf (shared_memory, "Hello, world.");
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Reattach the shared memory segment, at a different address. */
shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0);
printf ("shared memory reattached at address %p\n", shared_memory);
/* Print out the string from shared memory. */
printf ("%s\n", shared_memory);
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Deallocate the shared memory segment. */
shmctl (segment_id, IPC_RMID, 0);
return 0;
}
Hier ist ein mmap-Beispiel:
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/*
* pvtmMmapAlloc - creates a memory mapped file area.
* The return value is a page-aligned memory value, or NULL if there is a failure.
* Here's the list of arguments:
* @mmapFileName - the name of the memory mapped file
* @size - the size of the memory mapped file (should be a multiple of the system page for best performance)
* @create - determines whether or not the area should be created.
*/
void* pvtmMmapAlloc (char * mmapFileName, size_t size, char create)
{
void * retv = NULL;
if (create)
{
mode_t origMask = umask(0);
int mmapFd = open(mmapFileName, O_CREAT|O_RDWR, 00666);
umask(origMask);
if (mmapFd < 0)
{
perror("open mmapFd failed");
return NULL;
}
if ((ftruncate(mmapFd, size) == 0))
{
int result = lseek(mmapFd, size - 1, SEEK_SET);
if (result == -1)
{
perror("lseek mmapFd failed");
close(mmapFd);
return NULL;
}
/* Something needs to be written at the end of the file to
* have the file actually have the new size.
* Just writing an empty string at the current file position will do.
* Note:
* - The current position in the file is at the end of the stretched
* file due to the call to lseek().
* - The current position in the file is at the end of the stretched
* file due to the call to lseek().
* - An empty string is actually a single '\0' character, so a zero-byte
* will be written at the last byte of the file.
*/
result = write(mmapFd, "", 1);
if (result != 1)
{
perror("write mmapFd failed");
close(mmapFd);
return NULL;
}
retv = mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0);
if (retv == MAP_FAILED || retv == NULL)
{
perror("mmap");
close(mmapFd);
return NULL;
}
}
}
else
{
int mmapFd = open(mmapFileName, O_RDWR, 00666);
if (mmapFd < 0)
{
return NULL;
}
int result = lseek(mmapFd, 0, SEEK_END);
if (result == -1)
{
perror("lseek mmapFd failed");
close(mmapFd);
return NULL;
}
if (result == 0)
{
perror("The file has 0 bytes");
close(mmapFd);
return NULL;
}
retv = mmap(NULL, size,
PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0);
if (retv == MAP_FAILED || retv == NULL)
{
perror("mmap");
close(mmapFd);
return NULL;
}
close(mmapFd);
}
return retv;
}
open fügt Datei-I/O-Overhead hinzu. Verwenden shm_open stattdessen.
während einige shm_open()-Implementierungen open() unter der Haube verwenden, stellt POSIX geringere Anforderungen an die von shm_open() erzeugten Dateideskriptoren. Zum Beispiel sind Implementierungen nicht erforderlich, um E/A-Funktionen wie read() und write() für shm_open()-Dateideskriptoren zu unterstützen, wodurch bestimmte Implementierungen Optimierungen für shm_open() vornehmen können, die für open() nicht möglich sind. Wenn Sie damit nur mmap() machen, sollten Sie shm_open() verwenden.
– osven
9. April 2018 um 20:46 Uhr
Die meisten Linux-glibc-Setups machen eine solche Optimierung, indem sie tmpfs verwenden, um shm_open() zu unterstützen. Während auf dieselben tmpfs normalerweise über open() zugegriffen werden kann, gibt es keine portable Möglichkeit, ihren Pfad zu erfahren. Mit shm_open() können Sie diese Optimierung portabel verwenden. POSIX gibt shm_open() das Potenzial, besser als open() zu funktionieren. Nicht alle Implementierungen werden dieses Potenzial nutzen, aber es wird nicht schlechter abschneiden als open(). Aber ich stimme zu, dass meine Behauptung, dass open() immer Overhead hinzufügt, zu weit gefasst ist.
– osven
9. April 2018 um 20:50 Uhr
open fügt Datei-I/O-Overhead hinzu. Verwenden shm_open stattdessen.
während einige shm_open()-Implementierungen open() unter der Haube verwenden, stellt POSIX geringere Anforderungen an die von shm_open() erzeugten Dateideskriptoren. Zum Beispiel sind Implementierungen nicht erforderlich, um E/A-Funktionen wie read() und write() für shm_open()-Dateideskriptoren zu unterstützen, wodurch bestimmte Implementierungen Optimierungen für shm_open() vornehmen können, die für open() nicht möglich sind. Wenn Sie damit nur mmap() machen, sollten Sie shm_open() verwenden.
– osven
9. April 2018 um 20:46 Uhr
Die meisten Linux-glibc-Setups machen eine solche Optimierung, indem sie tmpfs verwenden, um shm_open() zu unterstützen. Während auf dieselben tmpfs normalerweise über open() zugegriffen werden kann, gibt es keine portable Möglichkeit, ihren Pfad zu erfahren. Mit shm_open() können Sie diese Optimierung portabel nutzen. POSIX gibt shm_open() das Potenzial, besser als open() zu funktionieren. Nicht alle Implementierungen werden dieses Potenzial nutzen, aber es wird nicht schlechter abschneiden als open(). Aber ich stimme zu, dass meine Behauptung, dass open() immer Overhead hinzufügt, zu weit gefasst ist.
– osven
9. April 2018 um 20:50 Uhr
14242100cookie-checkSo verwenden Sie Shared Memory mit Linux in Cyes
Sie können erwägen, Threads anstelle von Prozessen zu verwenden. Dann wird der gesamte Speicher ohne weitere Tricks geteilt.
– Elomage
4. Februar 2014 um 12:22 Uhr
Die folgenden Antworten behandeln sowohl den System V IPC-Mechanismus,
shmget()
et al. und auch das reinemmap()
Ansatz mitMAP_ANON
(akaMAP_ANONYMOUS
) – obwohlMAP_ANON
wird nicht von POSIX definiert. Es gibt auch POSIXshm_open()
undshm_close()
zur Verwaltung von Shared-Memory-Objekten. […continued…]– Jonathan Leffler
15. März 2020 um 3:59 Uhr
[…continuation…] Diese haben den gleichen Vorteil wie der gemeinsam genutzte IPC-Speicher von System V – das gemeinsam genutzte Speicherobjekt kann über die Lebensdauer des Prozesses hinaus bestehen bleiben, der es erstellt (bis ein Prozess ausgeführt wird
shm_unlink()
), während Mechanismen mitmmap()
erfordern eine Datei undMAP_SHARED
um die Daten zu speichern (undMAP_ANON
verhindert Persistenz). Es gibt ein vollständiges Beispiel im Begründungsabschnitt der Spezifikation vonshm_open()
.– Jonathan Leffler
15. März 2020 um 4:01 Uhr