[OSy] thread_create && robust_thread_create
Martin Decky
decky at d3s.mff.cuni.cz
Mon Nov 3 00:04:07 CET 2014
Hezký večer,
> 1)
> technický dotaz - v testech se některé funkce vyskytují ve variantě robust, není mi příliš jasné, co se od této varianty očekává
Tyto obalové funkce nebo makra robust_* nemusíte definovat. Zdrojáky
testů si je definují samy (viz include/defs.h ve stromě testů).
> čím se mají tyto robust funkce lišit od původních? Respektive k čemu slouží?
Důvod pro použití těch robust_* funkcí/maker je ten, aby samotná
"business logika" testů mohla být zapsána kompaktně a rutinní ošetřování
návratových hodnot a podobných záležitostí (které je však potřeba udělat
důsledně a vždy) zdrojový kód testu zbytečně neznepřehledňovalo.
> 2)
> dost mě matou parametry funkce thread_create:
> thread_t * thread_ptr - předpokládám, že se jedná o lokaci nového vlákna, takže malloc musím volat ještě před voláním thread_create?
Ne. Argument thread_ptr je skutečně výstupní argument funkce
thread_create() a v souladu s obecnými zásadami zadání se předpokládá,
že alokaci potřebné paměti pro nové vlákno zajistí samotná funkce
thread_create().
Obecné poznámky k rozhraní jádra totiž říkají, že typ thread_t skrývá
před volajícím implementační detaily. Proto můžete typ thread_t klidně
implementovat jako číselný identifikátor vlákna (handle) nebo jako
ukazatel na strukturu vlákna. Záleží na Vašem rozhodnutí.
> protože abych mohl tenhle pointer předat navenek, musel bych v parametrech dostat ne pointer na vlákno, ale pointer na pointer na vlákno
Je-li typ thread_t definován jako pointer na vlákno, potom první
argument funkce thread_create() je skutečně pointer na pointer na vlákno.
> Takže při tvoření vlákna první malloc(sizeof(thread_to_be_created)) a potom thread_create?
Zkuste zapřemýšlet, zda by takový způsob použití thread_create()
odpovídal zadání a zda by to nevyžadovalo změnu testů.
> void *(*thread_start)(void *) - ukazatel na zacatek funkce, kterou mám z vlákna zavolat - takže poté, co vlákno stvořím, mám nějak zavolat tuhle funkci?
Nejsem si jistý, jestli dobře rozumím otázce. Argument thread_start
ukazuje na tělo vlákna, tj. na kód, který má vlákno začít provádět (po
svém prvním naplánování).
Pokud potřebujete vidět analogii s jiným prostředím, tak thread_start má
stejnou roli jako např. metoda run() v případě interfacu Runnable v Javě.
> Jak velkou část tohoto pokrývá fce thread_init?
Přiznám se, že netuším, co myslíte pod funkcí thread_init. Na co se
odkazujete?
> void * data - kde má fce v paměti uložená data, nějak nakrmit do fce thread_start - rád nakrmím, pokud se mi podaří zjistit, jak...
Třetí argument funkce thread_create() je potřeba předat funkci
thread_start jako její první argument po prvním naplánování vlákna.
Zkuste se zamyslet nad tím, jak vlastně zajistíte, že poprvé naplánované
nové vlákno začne provádět kód od místa v paměti určeného ukazatelem
thread_start. Předání argumentu tomuto kódu je potom už snadný další krok.
> 3)
> jaký je důvod, že na vlákno může čekat jenom jedno jiné vlákno?
Abych to ještě upřesnil: Ve skutečnosti na vlákno (pokud není detached)
musí čekat _právě_jedno_ jiné vlákno.
Proč tomu tak je? To je velmi důležitá otázka a doporučuji Vám velmi
důkladně se nad těmi důvody zamyslet. Můžete například začít úvahou, jak
by vypadala terminální podmínka pro uvolnění struktury vlákna (resp.
recyklace identifikátoru vlákna) v případě, že byste umožnil čekání více
vláken na ukončení běhu jednoho vlákna.
> respektive čekal bych frontu, která bude probuzena po skončení vlákna na které čekají, první z fronty, který se dostane k lizu bude ok a zbylí buď taky a nebo se přeřadí a budou čekat na toho, který měl štěstí...
Takový daisy-chain mechanismus je pochopitelně v principu možný. Ale sám
o sobě nevyřeší otázku terminální podmínky pro uvolnění paměti vlákna --
řekl bych, že tu záležitost právě naopak velmi zkomplikuje.
Proto zadání semestrální práce nepožaduje žádné takové řešení, jehož
složitost je možná srovnatelná s celým zbytkem zadání, ale požaduje jen
tradiční rozhraní pro čekání na vlákna, které je implementovatelné
celkem snadno a přímočaře.
> 4)
> co se vláken týče, používá se nějaká tabulka pro všechny vlákna? - ta naplánovaná jsou v listu scheduleru, ale kde jsou ty zbylá? některá si občas někdo pamatuje, ale co třeba s takovým vláknem, které si zavolá suspend a nikdo ho nebudí - bude čekat do skonání světa?
> a kdy uvolnit samotnou strukturu vlákna(dejme tomu že při kill detached vlákna je to ok, ale co s vláknem, které jenom zabiju - kdy se ho zbavit? (protože když se někdo snaží o join na killed vlákno, mám vyhodit EKILLED)...
Myslím, že si kladete velmi rozumné otázky, a věřím, že když se nad nimi
sám důkladně zamyslíte, tak dojdete také k rozumným odpovědím.
Toto všechno jsou skutečně záležitosti, které musí být správně navrženy
a implementovány, aby jádro operačního systému fungovalo správně a
konzistentně. Nicméně především z toho implementačního hlediska existuje
rozhodně více než jedno správné řešení, takže bych Vám jen nerad
podsouval zrovna svou představu.
Jen drobný hint: Uživatelský prostor si může v principu vymyslet
libovolný identifikátor vlákna a jádro by mělo být schopno vždy
jednoznačně poznat, zda je takový identifikátor skutečně platný nebo ne.
M.D.
More information about the NSWI004
mailing list