kopiowanie do pamięci sharowanej za pomocą memcpy

Odpowiedz Nowy wątek
2019-08-28 16:29
fvg
0

Hej
Mam problem z którym nie jestem w stanie kompletnie sobie poradzić.
Nie działa mi memcpy do pamięci sharowanej. Poniżej kawałek kodu pokazujący jak tworze pamięć sharowana, inicjalizuję ją i output po inicjalizacji. Ze względu na to że kod spawany w firmie X w locie musiałem zmienić nazwy toteż mogłem coś pominąć więc na takie literówki prosze nie zwracac uwagi:

struct Struktura
{
        unsigned number;
    std::string name;
    unsigned value;
};

const std::array<Struktura, 9> lista=
{{
    { 0, "nazwa__0", 1 },
    { 1, "nazwa__1", 0 },
    { 2, "nazwa__2", 1 },
    { 3, "nazwa__3", 0 },
    { 4, "nazwa__4", 0 },
    { 5, "nazwa__5", 0 },
    { 6, "nazwa__6", 0 },
    { 7, "nazwa__7", 0 },
    { 888, "nazwa__888", 456 }
}};

Mam metodę która zwraca 146 bajtów (tyle okupuje tablica) i to przypisuje poprzez konstruktor do mSizeInBytes, tworze pamięć sharowaną:

    //create and opens shared memory object
         mMd = shm_open(mSharedMemPath.c_str(), O_RDWR | O_CREAT, S_IRWXO|S_IRWXG|S_IRWXU);
    if(mMd < 0)
    {
        perror("shm_open failure");
        return false;
    }

    //extend to page alignment
    int pageAlignment = mSizeInBytes / pagesize + (mSizeInBytes % pagesize ? pagesize : 0);
    std::cout << "Page alignment: " << pageAlignment << std::endl;
    if(ftruncate(mMd, pageAlignment) == -1) //tutaj 4096 bajtów pageAlignment wynosi
    {
        perror("ftruncate failure");
        close();
        unlink();
            return false;
    }

    //maps memory object into process virtual address space
    mPtr = static_cast<T*>(mmap(NULL, mSizeInBytes, PROT_WRITE | PROT_READ, MAP_SHARED, mMd, 0));
    if(mPtr == MAP_FAILED)
    {
        perror("mapping failed");
        close();
        unlink();
        return false;
    }

No i potem inicjalizuje pamięć sharowaną danymi z listy:

    for(u32 i = 0; i<lista.size(); ++i)
    {
        std::cout << "Init data: " << lista[i].number << ", " << lista[i].name << ", value = " << lista[i].value << std::endl;
    }

    std::cout << "Copy " << mSizeInBytes << " [bytes] to shared mem area" << std::endl;

    memcpy(mPtr, lista.data(), mSizeInBytes); //mPtr wskaznik z mmap, lista.data() wskaźnik na dane z listy, mSizeInBytes=146

//po skopiowaniu sprawdzam i nie działa:/:
    for(u32 i = 0; i<lista.size(); ++i)
    {
        std::cout << "data in shmem: " << mPtr[i].number << ", " << mPtr[i].name << ", value = " << mPtr[i].value << std::endl;
    }

Jako output mam, że tylko pierwszych 5 itemów z listy się skopiowało a dalej same zera:

data in shmem: 0, nazwa0, value = 1
data in shmem: 1, nazwa
1, value = 0
data in shmem: 2, nazwa2, value = 1
data in shmem: 3, nazwa
3, value = 0
data in shmem: 4, nazwa__4, value = 0
data in shmem: 0, , value = 0
data in shmem: 0, , value = 0
data in shmem: 0, , value = 0
data in shmem: 0, , value = 0

Aha jeszcze ważna rzecz - mPtr jest typu T a tam mamy szablon klasy i jako T przekazuję Struktura.

edytowany 1x, ostatnio: fvg, 2019-08-28 16:33

Pozostało 580 znaków

2019-08-28 16:31
kq

std::string to tak naprawdę 3 wskaźniki (begin, end, capacity), i nie można go serializować za pomocą memcpy. Do tego zastosowania zapewne lepiej nada się głupia tablica array<char, N>


to tak naprawdę 3 wskaźniki – ale uściślijmy że to implementation dependent, bo jeszcze ktoś zacznie na tym polegać :D - Azarien 2019-08-29 15:07
Racja. Ale ze słownictwa w standardzie wynika, że musi być pointer, (size_t|pointer), (size_t|pointer). Ale faktycznie nie ma co polegać na detalach implementacyjnych. - kq 2019-08-29 19:31

Pozostało 580 znaków

2019-08-28 16:41
fvg
0

tak to był problem ze stringiem, jak w Struktura zmieniłem typ pola 'name' na 'const char*' to juz problem nie występuje.

Pozostało 580 znaków

2019-08-28 16:42
kq
0

To ma być pamięć dostępna z wielu procesów? W takim razie wskaźnik musi wskazywać na poprawny adres w każdym z tych procesów (u Ciebie tak nie będzie), dlatego sugerowałem bezpośrednio tablicę.


Pozostało 580 znaków

2019-08-28 16:56
fvg
0

Tak z wielu procesów. Ale to powinno działać, bo dane z listy (146 bajtów) są kopiowane do pamięci sharowanej w procesie pierwszym i lista już nie jest używana. Więc to już mi powinno zapewnić, że jak włączę drugi proces i wykonam na tej pamięci:

memDesriptor = shm_open(...)
Struktura* mPtr = mmap(..., memDescriptor)

to mPtr wskaźe na te dane, które pierwszy proces tu skopiował. Wiadomo jeszcze semaforem nazwanym będę musiał kontrolować zapis/odczyt danych.

edytowany 1x, ostatnio: fvg, 2019-08-28 16:57

Pozostało 580 znaków

2019-08-28 17:01
1
fvg napisał(a):

tak to był problem ze stringiem, jak w Struktura zmieniłem typ pola 'name' na 'const char*' to juz problem nie występuje.

Ale to nie może być const char* bo to nadal są wskaźniki, które w innym procesie nie mają sensu. Jeśli ci to działa to cudem, albo po prostu nie opisałeś dodatkowych zmian.
Jak ci kq pisał o tablic to miał na myśli: char name[256] (proste rozwiązanie marnujące pamięć i dające limit na rozmiar napisu).

Najlepiej by było, jakbyś po prostu użył protobuf.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 3x, ostatnio: MarekR22, 2019-08-28 17:03

Pozostało 580 znaków

2019-08-29 10:43
fvg
0

Rzeczywiście nie działa bez zmiany z const char* na const char name[40].

Pozostało 580 znaków

2019-08-29 15:41
1

Tak poza konkursem - jak z wielu procesów chcesz tej pamięci używać to pomyśl czy volatile nie byłoby w paru miejscach wskazane.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0