maanantai 21. heinäkuuta 2008

Muistin jakaminen DLL:n kautta

Windowsissa prosessien on mahdollista jakaa muistia DLL:n kautta. Kun DLL:n muistialue merkitään jaetuksi, järjestelmä kuvaa muistin siten, että jokainen jaetuksi merkittyä muistialuetta käyttävä prosessi näkee saman fyysisen muistialueen. Tällaisen jaetun muistialueen avulla prosessit voivat kommunikoida.

Kirjoitin C:llä yksinkertaisen demon jaetun muistin käytöstä. Kaikki netistä löytämäni demot oli kirjoitettu C++:lla ja niissä oli lähes poikkeuksetta graafisia käyttöliittymiä, joiden toteuttamiseen tarvittavien koodirivien varjoon demon kannalta oleellinen koodi jää. Graafinen käyttöliittymä on mielestäni hätävarjelun liioittelua, joten minun demossani ei ylimääräisiä rivejä ole.

Demo koostuu kolmesta ohjelmasta: SharedDataSegmentDLLHostingApplication, SharedDataValueIncrementer ja SharedDataValuePrinter. Jaetun muistialueen sekä sen manipulointiin tarvittavat funktiot sisältävä DLL on nimeltään SharedDataSegmentDLL.

SharedDataSegmentDLL

Kun käytetään GCC:tä, DLL:ään voidaan koodata jaettu kokonaislukumuuttuja seuraavasti:
int sharedInteger __attribute__((section ("shared"), shared)) = 0;
Microsoftin kääntäjä/linkitin haluaa nähdä rivit
#pragma data_seg (".shared")
int sharedInteger = 0;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")
Tässä on siis määritelty kokonaisluku sharedInteger jaetuksi. Muuttuja on alustettava kuten yllä on esitetty. Muuttujan arvo voidaan lukea yksinkertaisesti tekemällä DLL:ään funktio PrintSharedDataValue():
DLLEXPORT void PrintSharedDataValue() {

printf("%i", sharedInteger);

}
Muuttujan arvoa voidaan muuttaa funktiolla IncrementSharedDataValue():
DLLEXPORT void IncrementSharedDataValue() {
sharedInteger++;
}
Tässä DLLEXPORT on määritelty siten, että kääntäjä ymmärtää, että DLL:n lataavien prosessien on tarkoitus käyttää funktiota:
#ifndef DLLEXPORT
#define DLLEXPORT __declspec(dllexport) // export DLL information
#endif
Lisäksi tarvitaan funktio DLLSleep(). Jos nimittäin HostingApplication kutsuisi vain Win32 API:n Sleep()-funktiota, Windowsin lataimella ei olisi mitään syytä ladata SharedDataSegmentDLL:ää. Kun DLL:ään koodataan DLLSleep():
DLLEXPORT void DLLSleep() {
Sleep(INFINITE);
}
ja kutsutaan tätä funktiota HostingApplicationissa,
Windowsin on pakko ladata DLL. Tällöin jaettu muuttuja tulee samalla alustetuksi.

SharedDataSegmentDLLHostingApplication

Tämän ohjelman tarkoitus on pysyä käynnissä ja pitää SharedDataSegmentDLL ladattuna muistissa. Ohjelma on varsin yksinkertainen:

#include "../header/dll.h"


DLLIMPORT void DLLSleep();

int main(int argc, char *argv[])
{
DLLSleep();
}
DLLIMPORT kertoo, että on tarkoitus käyttää DLL:ssä määriteltyä funktiota DLLSleep(). DLLIMPORT on määritelty tiedostossa dll.h. Muuta main()-funktiossa ei sitten tarvitsekaan tehdä. SharedDataSegmentDLLHostingApplication nukkuu ikuisesti ja pitää DLL:n muistissa.

SharedDataValueIncrementer

SharedDataValueIncrementer kasvattaa jaetun kokonaisluvun arvoa kutsumalla funktiota IncrementSharedDataValue():
#include "../header/dll.h"

DLLIMPORT void IncrementSharedDataValue();

int main(int argc, char *argv[])
{
IncrementSharedDataValue();
}

SharedDataValuePrinter

SharedDataValuePrinter tulostaa jaetun kokonaislukumuuttujan arvon kutsumalla funktiota PrintSharedDataValue()
#include "../header/dll.h"

DLLIMPORT void PrintSharedDataValue();

int main(int argc, char *argv[])

{

PrintSharedDataValue();

}

Ohjelmiston kääntäminen

Olen määritellyt dll.h:n sijainniksi ../header, jolloin jokainen lähdekooditiedosto sijaitsee omassa hakemistossaan ja dll.h header-hakemistossa. Lisäksi kääntäjää voi joutua neuvomaan etsimään otsaketiedostoja header-hakemistosta. DLL on käännettävä ensin, koska sitä tarvitaan ohjelmien kääntämiseksi. Kääntäjälle on kerrottava, että sen tulee käyttää DLL:ää vastaavaa lib-tiedostoa.

Ohjelmiston käyttö

SharedDataDLLHostingApplication käynnistetään komentotulkista. Toisesta komentotulkista käytetään SharedDataValuePrinteriä ja SharedDataValueIncrementeriä, jonka pitäisi kasvattaa muuttujan arvoa yhdellä jokaisella ajokerralla. Jos muuttujan arvo ei muutu, muuttujan määrittely jaetuksi ei ole onnistunut. DLL:n pitää sijaita samassa hakemistossa kuin ohjelmat.

Lähdekoodi

Lähdekoodia saa käyttää vapaasti.

dll.h (teksti) (HTML)
SharedDataSegmentDLL.c (teksti) (HTML)
SharedDataSegmentDLLHostingApplication.c (teksti) (HTML)
SharedDataValueIncrementer.c (teksti) (HTML)
SharedDataValuePrinter.c (teksti) (HTML)
SharedDataSegmentDemoGCC.zip

Ei kommentteja: