Hlavní navigace

GLib: Cache

7. 2. 2001
Doba čtení: 4 minuty

Sdílet

Pod pojmem "cache" v knihovně GLib nenajdete přesně to, co znamená cache v terminologii kolem hardwaru. Nejedná se o vyrovnávající paměť zrychlující práci s pomalými zařízeními, ale i tak je to docela užitečný mechanizmus, který občas můžete potřebovat.

Předem bych rád podotknul, že jsem se rozhodl slovo cache počeštit, a psát místo něj jednoduše „keš“. Je to z toho důvodu, že samotné „cache“ se nedá vůbec skloňovat a v mnoha případech by proto mohlo dojít k nedorozumění. Snad mi to pan Jungmann promine :-).

Jak to funguje

Datový typ GCache je jako obvykle neveřejná struktura:

struct GCache;

My si nyní popíšeme, k čemu je dobrá.

GCache slouží ke sdílení velkých datových struktur, aby se zbytečně neplýtvalo hardwarovými prostředky (operační pamětí).

GCache najde své uplatnění hlavně v situacích, kdy uchováváte jakési informace o „vlastnostech“ nějakých objektů. Napadají mě například údaje o povrchu a texturách těles v grafických programech, možná definice fontů a podobně. Knihovna GTK například používá keš k ukládání stylů ( GtkStyle, v těchto stylech se uchovávají barvy, použitá pozadí, fonty a podobně).

Ačkoliv může existovat mnoho různých druhů textur, fontů nebo GTK stylů, všechny mají jedno společné: je-li jednou definován nějaký konkrétní druh, je od té doby v jistém smyslu konstantní. Není asi vhodné, aby povrch každého objektu, kterému přiřadíme texturu „mramor“, vypadal úplně jinak.

Díky keši GCache máte možnost docílit toho, že ačkoliv nějakou konkrétní vlastnost přiřadíte mnoha objektům, ve skutečnosti bude v paměti uložena jen v jednom exempláři.

Údaje uložené v keši jsou identifikovány jednoznačným klíčem. GCache je tvořena hash tabulkami, ve kterých pro vnitřní potřebu uchovává spojení klíč-data a data-klíč. O každých datech se ještě udržuje údaj o počtu existujících ukazatelů na ně.

Na žádost o získání pointeru na sdílená data podle klíče se nejprve zjistí, jsou-li vůbec žádané hodnoty k dispozici. V kladném případě se vrátí pointer na ně a zvýší se jejich počítadlo ukazatelů. Pokud data s určeným klíčem neexistují, dojde k jejich vytvoření.

Po skončení práce s daty se musí nástroji GCache sdělit, že už hodnoty nepotřebujeme a GCache počítadlo ukazatelů sníží. Klesne-li počet ukazatelů na nulu, GCache data i klíč z paměti uvolní. Veškeré hlídání toho, která data máme v paměti a která ne, která ještě potřebujeme a která jsou naopak zbytečná, s keší GCache úplně odpadá.

Vytvoření nové keše GCache

Funkce

GCache* g_cache_new(GCacheNewFunc value_new_func,
                    GCacheDestroyFunc value_destroy_func,
                    GCacheDupFunc key_dup_func,
                    GCacheDestroyFunc key_destroy_func,
                    GHashFunc hash_key_func,
                    GHashFunc hash_value_func,
                    GCompareFunc key_compare_func);

gpointer (*GCacheNewFunc) (gpointer key);
void (*GCacheDestroyFunc) (gpointer value);
gpointer (*GCacheDupFunc) (gpointer value);

…slouží k vytvoření nové keše GCache.

value_new_func je uživatelská funkce typu GCacheNewFunc, která má za úkol podle předaného klíče vytvořit odpovídající sdílený datový záznam. Funkce je volána rutinou g_cache_insert() v případě, že jsou uživatelem požadována data, která se v keši ještě nevyskytují.

value_destroy_func je funkce, která bude volána pro dealokaci sdílených dat.

key_dup_func musí být funkce, která vyrobí duplikát klíče a key_destroy_func funkce obstarávající dealokaci klíče.

Následují funkce, které budou využity pro ukládání klíčů a sdílených dat do hash tabulek. Očekává se, že hash_key_func bude funkce, která „vyrobí“ hash-hodnotu z klíče podobně jako hash_value_func, která se postará o výpočet hash-hodnoty z dat.

Posledním parametrem je key_compare_func od níž se očekává, že bude porovnávat dva klíče. Funkce key_compare_func by měla vracet TRUE, jsou-li dva klíče shodné a FALSE v ostatních případech.

Rutina g_cache_new() vrátí pointer na nově vytvořenou  GCache.

Práce s daty v keši GCache

gpointer g_cache_insert(GCache *cache, gpointer key);

…vrátí z GCache   cache pointer na sdílená data, která jsou připojena ke klíči key.

Funkce se nejprve pokusí nalézt data ve svých hash tabulkách s využitím funkce key_compare_func (viz g_cache_new()). Pokud údaje existují, vrátí pointer na ně a inkrementuje jejich počítadlo ukazatelů. Pokud údaje nenajde, zavolá funkci value_new_func, předá jí klíč key a ta se postará o vytvoření žádaných dat. Klíč je pak pomocí key_dup_func duplikován a spolu s daty uložen do hash tabulek příslušné keše cache. Vytvořená data se použijí jako návratová hodnota a jejich počítadlo ukazatelů se nastaví na 1.

void g_cache_remove(GCache *cache, gpointer value);

…touto funkcí dává programátor najevo, že skončil pracovat s daty value. GCache cache dekrementuje jejich počítadlo ukazatelů a jestliže ono klesne na 0, sdílená data i jejich příslušný klíč se uvolní z paměti pomocí funkcí value_destroy_func a key_destroy_func (viz  ()).

Dealokace keše GCache

void g_cache_destroy(GCache *cache);

…uvolní paměť potřebnou pro GCache cache. Funkce v žádném případě nedealokuje sdílená data ani klíče, které jsou v keši uloženy. Navíc, pokud jsou mé předpoklady správné, nedealokuje ani jisté vnitřní struktury, ve kterých se uchovávají počítadla ukazatelů, takže pokud chcete mít jistotu, že jste uvolnili opravdu veškerou paměť, provádějte g_cache_destroy() výhradně nad prázdnou keší (tj. všechna sdílená data nejprve odstraňte příslušným počtem volání  g_cache_remove()).

Dokončení příště.

Byl pro vás článek přínosný?

Autor článku

Michal Burda vystudoval informatiku a aplikovanou matematiku a nyní pracuje na Ostravské univerzitě jako odborný asistent. Zajímá se o data mining, Javu a Linux.