shmget - semaforos en c
Cómo usar la memoria compartida con Linux en C (6)
Aquí hay un ejemplo de memoria compartida. Esto podría ayudar:
#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: */
data = shmat(shmid, (void *)0, 0);
if (data == (char *)(-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;
}
Pasos: 1- Utilice ftok para convertir un nombre de ruta y un identificador de proyecto en una clave de IPC del sistema V
2- Usar shmget que asigna un segmento de memoria compartida
3- Utilice shmat para adjuntar el segmento de memoria compartida identificado por shmid al espacio de direcciones del proceso de llamada
4- Hacer las operaciones en el área de memoria
5- Separar usando shmdt
Tengo un problema con uno de mis proyectos.
He estado tratando de encontrar un ejemplo bien documentado de uso de memoria compartida con fork()
pero sin éxito.
Básicamente, el escenario es que cuando el usuario inicia el programa, necesito almacenar dos valores en la memoria compartida: current_path que es un char * y un file_name que también es char * .
Dependiendo de los argumentos del comando, se inicia un nuevo proceso con fork()
y ese proceso necesita leer y modificar la variable current_path almacenada en la memoria compartida, mientras que la variable file_name es de solo lectura.
¿Hay un buen tutorial sobre memoria compartida con código de ejemplo (si es posible) al que me puede dirigir?
Gracias, bleepzter
Aquí hay un ejemplo de mmap:
#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;
}
Estos son incluidos para usar la memoria compartida
#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);
Hay dos enfoques: shmget
y mmap
. Hablaré de mmap
, ya que es más moderno y flexible, pero puedes echar un vistazo a man shmget
( o este tutorial ) si prefieres usar las herramientas antiguas.
La función mmap()
se puede usar para asignar almacenamientos intermedios de memoria con parámetros altamente personalizables para controlar el acceso y los permisos, y respaldarlos con el almacenamiento del sistema de archivos si es necesario.
La siguiente función crea un búfer en memoria que un proceso puede compartir con sus hijos:
#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_ANONYMOUS | MAP_SHARED;
// 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, 0, 0);
}
El siguiente es un programa de ejemplo que usa la función definida anteriormente para asignar un búfer. El proceso principal escribirá un mensaje, tenedor, y luego esperará a que su hijo modifique el búfer. Ambos procesos pueden leer y escribir la memoria compartida.
#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);
}
}
prueba este ejemplo de código, lo probé, fuente: http://www.makelinux.net/alp/035
#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;
}
El capítulo 5 del libro "Advanced Linux Programming" tiene una buena introducción a IPC con Linux (todo el libro como pdf)