2016-11-03 47 views
5

Mam wspólną tablicę dynamiczną w modelu POSIX między dwiema różnymi aplikacjami. Chciałbym mieć możliwość zmiany jego rozmiaru bez kopiowania. Niestety nie mogłem znaleźć odpowiedniego rozwiązania, aby zwiększyć i zmniejszyć pamięć współdzieloną POSIX w języku C. W Internecie znalazłem wiele dokumentów o złych wyjaśnieniach i przykrych przykładach. Udało mi się znaleźć kilka ciekawych tematów, ale wszystkie z nich nadają się do mnie:Zmiana rozmiaru pamięci współużytkowanej POSIX. Działający przykład:

  1. "Linux System Programming" - "Mapping Files into Memory" Part: "Resizing a Mapping" - gdzie ma działający przykład, aby zmienić rozmiar SHM.

  2. How do I implement dynamic shared memory resizing? - Tylko opis. Nie mam przykładu.

  3. mremap function failed to allocate new memory - Ulubiona odpowiedź działa nieprawidłowo.

  4. Fast resize of a mmap file

  5. Characteristics of mremap function in Linux

  6. mremap function failed to allocate new memory

  7. c/linux - ftruncate and POSIX Shared Memory Segments - rszshm nie używa mremap() w ogóle. Zamiast tego kopiuje pamięć. Najgorszy sposób.

Opracowałem przykład, ponieważ rozumiem dokumentację. Niestety nie działa poprawnie. Proszę mi doradzić, gdzie się mylę. I proszę, bądźcie tak mili, aby dać mi działający przykład.

W dokumentacji stwierdziłem, że muszę używać ftruncate() przed mremap(), ale nie mogłem znaleźć właściwej składni do ich używania. Poza tym, mremap() działa z wyrównanymi stronami pamięci. Jak prawidłowo zwiększyć pamięć współużytkowaną w tym przypadku?

/* main.c */ 
#define _GNU_SOURCE 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <fcntl.h> 
#include <sys/shm.h> 
#include <sys/stat.h> 
#include <sys/mman.h> 
#include <sys/types.h> 
#include <errno.h> 

int main(void) 
{ 
    size_t size_of_mem = 1024; 
    int fd = shm_open("/myregion", O_CREAT | O_RDWR, 
         S_IRWXO | S_IRUSR | S_IWUSR); 
    if (fd == -1) 
    { 
     perror("Error in shm_open"); 
     return EXIT_FAILURE; 
    } 

    if (ftruncate(fd, size_of_mem) == -1) 
    { 
     perror("Error in ftruncate"); 
     return EXIT_FAILURE; 
    } 

    void *shm_address = mmap(0, size_of_mem, 
          PROT_READ | PROT_WRITE | PROT_EXEC, 
          MAP_SHARED, fd, 0); 
    if (shm_address == MAP_FAILED) 
    { 
     perror("Error mmapping the file"); 
     return EXIT_FAILURE; 
    } 

    /* Increase shard memory */ 
    for (size_t i=0; i<1024; ++i){ 

     /* Does 8 align memory page? */ 
     size_t new_size_of_mem = 1024+(8*i); 

     if (ftruncate(fd, new_size_of_mem) == -1) 
     { 
      perror("Error in ftruncate"); 
      return EXIT_FAILURE; 
     } 

     /* 
      mremap() works with aligned memory pages. 
      How to properly increase shared memory in this case? 
     */ 
     void *temp = mremap(shm_address, size_of_mem, new_size_of_mem, MREMAP_MAYMOVE); 
     if(temp == (void*)-1) 
     { 
      perror("Error on mremap()"); 
      return EXIT_FAILURE; 
     } 

     size_of_mem = new_size_of_mem; 

    } 

    return 0; 
} 

Budowa:

$ gcc -g -O0 -ggdb -pipe -Wall -Wextra -Wpedantic -Wshadow -march=native -std=c11 -o ./main ./main.c -lrt 

Run:

$ ./main 
Error on mremap(): Bad address 
+0

Przynajmniej będziesz musiał zmierzyć rozmiary pod względem rozmiaru strony. zobacz 'getpagesize()' lub 'sysconf()'. A do dzielenia pamięci pomiędzy procesami trzeba znaleźć sposób na przekazanie nowego rozmiaru innym procesom. – joop

Odpowiedz

2

tracisz adres nowego przydzielonego/odwzorować pamięci przypisanej do temp.

Oznacza to, że od drugiego cyklu pętli for przenosisz już przeniesioną pamięć.

Po sprawdzeniu zwróconej wartości mnuap można ponownie wysłać nowy adres do wskaźnika shm_address.

void *temp = mremap(shm_address, size_of_mem, new_size_of_mem, MREMAP_MAYMOVE); 
if(temp == (void*)-1) 
{ 
    perror("Error on mremap()"); 
    return EXIT_FAILURE; 
} 

shm_address = temp; 
+0

Dziękuję bardzo. Teraz naprawdę działa bez błędów. Co powiesz na pozostające pytanie. mremap() działa z wyrównanymi stronami pamięci. Jak prawidłowo zwiększyć pamięć współużytkowaną w tym przypadku? –

+1

To jest ogromne pytanie. Opublikuj inne pytanie, aby uzyskać dobre wyjaśnienie od jakiegoś guru zarządzającego linuxem. Mogę tu powiedzieć, że jeśli parametr len podany przez wywołującego nie jest wyrównany na granicy strony, mapowanie jest zaokrąglane w górę do następnej pełnej strony.Bajty wewnątrz tej dodanej pamięci, pomiędzy ostatnim ważnym bajtem i końcem mapowania, są wypełnione zerami. Każdy odczyt z tego regionu zwróci zera. – LPs

+0

Jeszcze raz dziękuję. Bardzo przydatne! –