[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