[C++]Variables declareren in shared memory

Pagina: 1
Acties:

  • Thralas
  • Registratie: December 2002
  • Laatst online: 20:09
Ik heb een bestaande applicatie waarvan een aantal instanties (processes) draaien. Elke instantie maak gebruik van een hoop geheugen (voornamelijk voor structs en classes, en misschien een aantal primitive types) dat gevuld wordt met info uit een SQL database. Deze info is constant, en dus heeft elke instantie voor een groot deel dezelfde data in het geheugen.

Om het geheugenverbruik terug te brengen wilde ik gebruik maken van shared memory voor deze variabelen, zodat de eerste instantie van de applicatie die gestart wordt eenmaal de variabelen initialiseerd, en instanties die hierna gestart worden gebruik maken van hetzelfde stukje geheugen met de al gealloceerde en geinitialiseerde variabelen.

Het draait allemaal onder Windows, dus na wat onderzoek kwam ik uit op 'File Mappings' om zo een stuk shared geheugen te creëren - dit werkt perfect met onderstaande class die ik bij het starten van elk programma construct. De eerste print dat hij een nieuw blok shared geheugen heeft aangemaakt, verdere instanties verkrijgen een handle naar het door het andere proces gecreëerde geheugen.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    /* Attempt to open an existing file mapping */
    hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, TRUE, "myFileMapping");
    if(hMap != NULL) {
        printf("Using previously allocated shared memory");
    } else {
        /* Create new file mapping */
        hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, SHAREDMEM_SIZE, "myFileMapping");
        if(hMap != NULL) {
            printf("Allocated shared memory");
        } else {
            printf("Failed to allocate shared memory!");
        }
    }

    pShared = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
    if(pShared == NULL) {
        printf("MapViewOfFile failed!");
    }

Het probleem
Nu loop ik echter tegen een probleem aan: Hoe wijzig ik bestaande variabelen zo dat ze geheugen in de shared memory space toegewezen krijgen?

Zelf had ik een aantal ideeën:
  • Één SharedMemory class voor het allocaten van één shared memory 'space'. Hiernaar laat ik een private *SharedMemoryObject in de class pointen. SharedMemoryObject bevat dan een aantal member functions die pointers returned die naar specifieke stukken van het shared memory pointen. Met behulp van een static getObject kan ik het SharedMemoryObject waar dan ook binnen m'n source verkrijgen. Vervolgens zou ik alleen nog de variabeledeclaraties moeten wijzigen in iets als:
    C++:
    1
    
    RandomClass bigArray = SharedMemory::getObject()->getBigArrayPtr() 

    Het nadeel hiervan is dat ik van tevoren één groot stuk shared memory moet allocaten waarvan ik de size niet precies weet (of moet uitrekenen).
  • Een tweede idee was om per variabele die in de shared space opgeslagen moet worden een nieuwe SharedMemory class te constructen en hier dan dus apart een named(?) FileMapping voor te allocaten. De uitwerking hiervan was echter wat twijfelachtig - zeker om het simpel te houden zodat ik zo min mogelijk aan de variabelendeclaraties hoef aan te passen. Ik heb gedacht aan operator overloading, maar ik vraag me af of dat haalbaar is?
Kort samengevat
Heeft iemand een idee hoe dit het makkelijkst uit te werken is zodat er zo min mogelijk veranderd hoeft te worden aan bestaande variabelen (bijv. alleen declaratie)?

  • ZaZ
  • Registratie: Oktober 2002
  • Laatst online: 27-11 15:14

ZaZ

Tweakers abonnee

Ik zou gaan voor de eerste oplossing. Je vraagt gewoon een blok geheugen aan en moet die een beetje soortgelijk behandelen zoals je bij een binary file zou doen.
Als je allemaal 'losse' stukjes geheugen gaat aanvragen loop je makkelijk tegen andere problemen op. Bijv. als je gefragmenteerd geheugen hebt krijg je mogelijk na een aantal aanvragen ineens geen shared mem toegewezen. Als dit allemaal 1 operatie is is het over het algemeen iets wat makkelijker af te handelen, maar dat ligt er natuurlijk aan hoe je het opzet :p

Mijn eerste ingeving is dat je 2 blokken alloceert: eentje om de boel te managen (zoals een header in een file) en een voor de data zelf.
Ik heb natuurlijk geen idee van hoe de applicatie precies in elkaar steekt, maar je kunt misschien een ruwe schatting maken van hoeveel geheugen er ongeveer nodig is en als toch het tekort is later vergroten.

Lekker op de bank


  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je zou natuurlijk ook objectjes kunnen definieren die in hun constructor de hoeveelheid benodigd geheugen rapporteert aan de shared memory manager, zodat hij wél weet hoeveel hij moet alloceren

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// interface for constructing/destructing types
class ObjectManager
{
public:
    virtual void construct(void * ptr) = 0;
    virtual void destruct() = 0;
};

// het object dat je variabelen registreert
template<class T> class SharedMemObject : private ObjectManager
{
public:
    SharedMemObject()
    {
        m_offset = SharedMemory::allocate(sizeof(T), this);
    }

    T * get() { return m_pObject; }
    const T * get() const { return m_pObject; }

    T * operator ->() { return get(); }
    T & operator *() { return *get(); }
    const T * operator ->() const { return get(); }
    const T & operator ->() const { return get(); }

private:
    void construct(void * ptr) { m_pObject = new(ptr) T(); }
    void destruct() { m_pObject->~T(); m_pObject = 0; }

    T * m_pObject;
};

// ...
struct MySharedStruct
{
    int i;
    float f;
    char henk[34];
};

SharedObject<MySharedStruct> myStruct;

int main()
{
    SharedMemory::init();
    myStruct->i = 34;
    strcpy(myStruct->henk, "Henk");
    SharedMemory::destroy();
}


SharedMem::allocate() reserveert uiteraard het aantal opgegeven bytes in de nog te alloceren buffer, en slaat de referentie na de ObjectManager instance op in een lijstje, tezamen met de bijbehorende offset in de buffer. Als je het shared mem alloceert ga je over dat lijstje heen en roep je construct() aan met de bijbehorende pointer. Bij het vrijgeven van het mem ga je wederom over het lijstje heen om destruct() aan te roepen.

[ Voor 23% gewijzigd door .oisyn op 22-11-2006 03:13 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Thralas
  • Registratie: December 2002
  • Laatst online: 20:09
ZaZ schreef op woensdag 22 november 2006 @ 02:36:
Mijn eerste ingeving is dat je 2 blokken alloceert: eentje om de boel te managen (zoals een header in een file) en een voor de data zelf.
Ik heb natuurlijk geen idee van hoe de applicatie precies in elkaar steekt, maar je kunt misschien een ruwe schatting maken van hoeveel geheugen er ongeveer nodig is en als toch het tekort is later vergroten.
Hier had ik ook aan gedacht, een ruwe schatting moet opzich wel mogelijk zijn. En het exacte verbruik is natuurlijk vervolgens wel bij te houden omdat het allocaten via een klasse zal moeten verlopen.
.oisyn schreef op woensdag 22 november 2006 @ 03:06:
Je zou natuurlijk ook objectjes kunnen definieren die in hun constructor de hoeveelheid benodigd geheugen rapporteert aan de shared memory manager, zodat hij wél weet hoeveel hij moet alloceren
Allereerst, mooi voorbeeld! Was zelf al aan de slag gegegaan met een template-based idee, al miste ik een aantal overloads. Echter vervolgens liep ik dus vast, ik kan wel SharedMemory::allocate aanroepen met een size en referentie naar het object, maar hoe weet een SharedMem manager instantie in een ander proces nu welke pointer hij moet returnen voor een declaratie van een variabele die al gedeclareerd en gevuld met data was?

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 30-11 00:17
Was voor dit soort dingen niet placement new bedacht?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

Met placement new new je een object in een opgegeven stuk geheugen, effectief roep je dus gewoon de constructor aan op een stuk ongeinitialiseerd geheugen (zie regel 27 van m'n codevoorbeeld).
maar hoe weet een SharedMem manager instantie in een ander proces nu welke pointer hij moet returnen voor een declaratie van een variabele die al gedeclareerd en gevuld met data was?
Tja, dan zul je op een of andere manier een generiek registratie-systeem moeten bedenken waarmee je kunt uitvogelen waar wat staat. Je zou in het begin van je geheugenblok bijvoorbeeld een stringtable kunnen maken waarin je verwijzingen naar objecten adhv een naam op kunt zoeken.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Thralas schreef op dinsdag 21 november 2006 @ 23:43:
Ik heb een bestaande applicatie waarvan een aantal instanties (processes) draaien. Elke instantie maak gebruik van een hoop geheugen (voornamelijk voor structs en classes, en misschien een aantal primitive types) dat gevuld wordt met info uit een SQL database. Deze info is constant, en dus heeft elke instantie voor een groot deel dezelfde data in het geheugen.
Kun je dan geen threads gebruiken in plaats van processen?

  • Thralas
  • Registratie: December 2002
  • Laatst online: 20:09
Helaas, dat gaat niet lukken gezien de verdere opzet van de applicatie. Mogelijk draait het op meerdere machines, en met dit shared memory model is er per machine vanzelf één process die alles allocate.

Iedereen bedankt, ik denk dat ik een heel eind kom met het template idee en iets van een GUID per object.

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Thralas schreef op donderdag 23 november 2006 @ 19:17:
Helaas, dat gaat niet lukken gezien de verdere opzet van de applicatie. Mogelijk draait het op meerdere machines, en met dit shared memory model is er per machine vanzelf één process die alles allocate.

Iedereen bedankt, ik denk dat ik een heel eind kom met het template idee en iets van een GUID per object.
Waarom zou dat niet lukken?
Pagina: 1