kopiowanie do pamięci sharowanej za pomocą memcpy

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, nazwa__0, value = 1
data in shmem: 1, nazwa__1, value = 0
data in shmem: 2, nazwa__2, 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.

1

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>

0

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

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ę.

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.

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.

0

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

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.

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