Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C++] Shared memory modulaire daemon

Pagina: 1
Acties:

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-11 14:21

LauPro

Prof Mierenneuke®

Topicstarter
Het gaat om een applicatie die domotica kan regelen. Kort gezegd handelt deze events (indien 2 poort 2 op module 3 hoog is) af op basis van policies, welke weer acties genereert (poort 1 op module 10 aan). Voordat ik het wil releasen (0.1) zit ik nog met een paar dingen die ik nog niet netjes heb uitgewerkt.

Op dit moment is er 1 shared library (lib) en een executable (app) en een tiental modules die on the fly kunnen worden geladen (libtool). Een voorbeeld van een module is een driver om I/O poorten aan te sturen, er zijn ook webinterfaces e.d..

Nu is het zo dat er binnen de daemon (als proces) een config-object wordt aangemaakt. Hier worden bijvoorbeeld basale zaken als het hoofdpad van de applicatie, lijst met modules e.d. in bijgehouden. Daarnaast zijn er een aantal controllers die de verschillende objecten beheren. Een kort voorbeeldje om een idee te hebben:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
class lpdConfig{
public:
    lpdConfig();
    ~lpdConfig();
    
    lpdModuleList modules;
    lpdDeviceList devices;
    
    lpdModuleController *modulecontroller;
    lpdDeviceController *devicecontroller;
    
    std::string approot;
};
Met de modulecontroller is het bijvoorbeeld mogelijk om te zoeken naar nieuwe modules, zo zijn er nog een aantal.

Het probleem is dat die lpdConfig eigenlijk een soort van shared memory is. Na wat gekloot met extern heb ik uiteindelijk besloten om gewoon een pointer naar dit object mee te geven als de controllers worden aangemaakt.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
lpdConfig::lpdConfig() {
    modulecontroller = new lpdModuleController(this);
    devicecontroller = new lpdDeviceController(this);
}

lpdConfig::~lpdConfig() {
    for(lpdModuleList::iterator iter = modules.begin(); iter != modules.end(); iter++) { delete *iter; }
    for(lpdDeviceList::iterator iter = devices.begin(); iter != devices.end(); iter++) { delete *iter; }
    
    delete modulecontroller;
    delete devicecontroller;
}
Kort gezegd is eigenlijk elke class verantwoordelijk voor zijn eigen geheugenmanagement. Ik ben bezig om dit consequent door te voeren.

Allereerst ben ik eigenlijk niet tevreden met de huidige opzet van het doorgeven van de lpdConfig. In mijn ogen vervuild dit te applicatie met allemaal loze verwijzingen als:
C++:
1
2
3
4
5
lpdModuleController::lpdModuleController(lpdConfig *config) : lpdSuperController(config)

lpdSuperController::lpdSuperController(lpdConfig *oConfig) {
    this->oCfg = oConfig;
}
Eigenlijk elk object moet die lpdConfig (pointer) lokaal 'cachen'.

Nu ben ik bezig geweest om met het extern keyword aan de slag te gaan en hiermee bijvoorbeeld een extern lpdConfig *shared_config neer te zetten in de lpdconfig.h. Probleem is echter dat ik dus gebruik maak van libtool en pthreads en voor zover ik het kunnen overzien kan je van libraries die je dynamisch laadt via libtool niet variabelen aan laten spreken gedeclareerd met het extern keyword. Daar heb ik dus een wrapper gemaakt die de pointer naar het configuratieobject doorgeeft (werkt verder perfect).

Wat is dus eigenlijk een nette manier om een gedeeld object te hebben tussen alle modules. Met daarbij niet het risico dat omdat module X bijvoorbeeld een speciale externe library nodig heeft (libxml++ ofzo) dat alle modules daartegen moeten worden gelinked.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-11 23:43

.oisyn

Moderator Devschuur®

Demotivational Speaker

Volgens mij kan het wel gewoon hoor, dat de parent application een symbol exposed wat door een shared library gereferenced wordt. Ik ben geen linux-hippie maar ik meen hier ooit eens mee geëxperimenteerd te hebben :). Het probleem was geloof ik om ervoor te zorgen dat dat symbool (shared_config) ook geexporteerd wordt in je main app, en daarvoor kon ik geen andere oplossing voor verzinnen dan alle symbols te exporteren. Maar je zou kunnen overwegen om een aparte shared lib te maken waar alleen die config in staat, zodat je die vanuit je app en vanuit andere shared libs kunt gebruiken.

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.


  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-11 14:21

LauPro

Prof Mierenneuke®

Topicstarter
Op dit moment omvat de shared lib eigenlijk alleen die config al. In principe zijn alle objecten in die lib ook weer ondergebracht in de config. (Op een aantal globale helperfuncties na.)

Eerlijk gezegd vind het nu teveel werk om nu al direct die shared config om te gooien. Ik zal er even mee experimenteren in een nieuwe branch.

Maar aan de ene kant is het hebben van globale variabelen niet netjes. Ik kan echter niet vinden wat nu netter is, deze rompslomp om overal die config beschikbaar te hebben of 1 enkele shared global (mits dat goed werkt zonder teveel gedoe).

Tweede wat ik nog wilde zeggen is of bijvoorbeeld verzamelingen als modules en devices in de controllers ondergebracht moeten worden of toch direct in de config. Een pre om ze in de controllers te stoppen is dat die die ook verantwoordelijk zijn, het nadeel is dat je bij het ophalen van een lijst je weer een extra header moet includen e.d. (die van de controller).

Eigenlijk zou je ook kunnen argumenteren dat die verzamelingen gewoon private in die controllers zouden moeten zitten, zij zijn immers verantwoordelijk daarvoor.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Verwijderd

Leuk project dat je aan het doen bent :) Je probleem is eigenlijk net zo oud als 'distributed' in het algemeen, dat is wat je in feite doet niet waar?

Wat ik niet helemaal snap is; waarom gebruik je geen IPC achtige constructies? Ik zelf gebruik rendevouz kanalen. Scheelt een heeel hoop gezeur, het kan zijn dat het niet toepasbaar is voor je maar dacht zeg het even.

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-11 14:21

LauPro

Prof Mierenneuke®

Topicstarter
Nou inmiddels het probleem kunnen oplossen, bleek een segfault ergens te zijn die het hele lpdConfig object verkrachtte. Nadat dit is opgelost werkt het als vanouds.

Er is overigens al een vorm van IPC, welliswaar via een socket, zo communiceren de modules weer met de core om events te sturen.

Her en der zijn nog wat memory leaks die ik even op moet lossen, dan kan de 0.1 de deur uit.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-11 14:21

LauPro

Prof Mierenneuke®

Topicstarter
Even een correctie, ik wilde hier eigenlijk geen implementatiedetails bespreken maar meer het hoofdonderwerp.

Wat is 'netter': Het hebben van 1 shared (extern) variabele door alle classen heen of het doorgeven van een pointer naar de configuratieklasse?

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Verwijderd

Volgens mij maakt het niet veel uit, maar in general heb ik zelf een hekel aan shared mem. Kern probleem is volgens mij synchronisatie -- in beide gevallen.

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-11 14:21

LauPro

Prof Mierenneuke®

Topicstarter
Syncronisatie wordt dmv mutexen geregeld, dat is al afgevangen. Ik beschouw het doorgeven van een pointer naar dat object niet echt als shared mem. Het is gewoon noodzaak.

Op zich zouden ook veel processen via IPC worden aangestuurd. Maar ik denk dat dat overkill is gezien het uiteindelijk gewoon 1 proces is (wel meerdere threads).

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!

Pagina: 1