Windows - Vlákna (Threads)

V procesu může běžet jedno nebo více vláken. Vlákno je základní jednotka vykonávání instrukcí programu, které systém přiděluje procesor. Každý proces startuje v primárním vláknu.
Všechna vlákna sdílejí stejný adresový prostor a systémové zdroje. Každé vlákno má vlastní handlery výjimek, prioritu a kontext. Kontext vlákna obsahuje registry, zásobník jádra a vlákna a prostředí vlákna v adresovém prostoru procesu. Vlákno může vykonávat libovolnou část kódu programu, včetně částí vykonávaných jiným vláknem.

Vytvoření vlákna

CreateThread
  • vytvoří nové vlákno procesu
  • musí se specifikovat startovací adresa kódu v lpStartAddress, typicky funkce tvaru DWORD WINAPI ThreadFunc( LPVOID );
  • vrací handle vlákna (který je platný dokud se neuzavře, tedy i po ukončení vlákna) a thread id do lpThreadId, při chybě NULL
  • priorita nového vlákna je THREAD_PRIORITY_NORMAL
  • lpParameter - parametr funkce vlákna
  • dwCreationFlags - další nastavení, např.
    • CREATE_SUSPENDED - vlákno je vytvořeno pozastavené, např. pro inicializaci, změnu priority, dokud jiné vlákno nezavolá ResumeThread

Je riskantní v parametru funkce vlákna předávat adresu lokální proměnné z vlákna, ze kterého vytváříme nové vlákno, protože původní vlákno může skončit dřív než nové a adresa by byla neplatná. Předávají se adresy na dynamicky alokovanou paměť nebo vlákno počká, až se ukončí nové vlákno.

PŘÍKLAD

Př. Napište program a vytvořte v něm nové vlákno.

CreateRemoteThread
  • vytvoří nové vlákno v jiném procesu, jehož handle je hProcess

OTÁZKA: Zjistěte podrobnější informace o vytvoření vlákna v jiném procesu. Např. musí funkce vlákna existovat v tomto nebo v cílovém procesu?

GetCurrentThreadId
  • vrací thread id vlákna

Př. Vypište id vlákna.

GetCurrentThread
  • vrací pseudo handle vlákna, který je použitelný jen v rámci tohoto vlákna !, lze jej "zveřejnit" na normální handle pomocí DuplicateHandle

Př. Zjistěte pseudo handle a "zveřejněný" pseudo handle vlákna a porovnejte ho s handlem z CreateThread.

SuspendThread
  • pozastaví vlákno, jehož handle je hThread, přesněji zvýší počet pozastavení vlákna
  • vrací počet pozastavení vlákna, při chybě 0xFFFFFFFF

Př. Pozastavte vlákno (z něj).

ResumeThread
  • sniží počet pozastavení vlákna, jehož handle je hThread, při 0 vlákno pokračuje
  • vrací počet pozastavení vlákna, při chybě 0xFFFFFFFF

Př. Pusťte vlákno.

Sleep
  • uspí vlákno na dwMilliseconds milisekund
  • když je dwMilliseconds INFINITE, vlákno se uspí navždy

GDI objekty (palety, kontexty zařízení, regiony, atd.) nejsou serializované, proto by se neměly sdílet.

Pro zamezení chybám souběhu (race conditions) a zablokování (deadlock) je potřeba synchronizovat přístup více vláken ke sdíleným prostředkům.

Ve vláknu je možné vytvořit okno, pak ale musí poskytovat smyčku zpráv, která bude vybírat zprávy z fronty zpráv.

Ukončení vlákna

ExitThread
  • ukončí toto vlákno s návratovým kódem dwExitCode

TerminateThread
  • ukončí jiné vlákno, jehož handle je hThread, s návratovým kódem uExitCode
  • vrací nenulovou hodnotu, při chybě 0

Vlákno se ukončí i když libovolné vlákno v procesu zavolá ExitProcess nebo TerminateProcess nebo když se ukončí funkce vlákna.

GetExitCodeThread
  • vrací status ukončení vlákna, jehož handle je hThread, do lpExitCode, je STILL_ACTIVE, pokud vlákno ještě běží, nebo je to návratový kód funkce vlákna
  • vrací nenulovou hodnotu, při chybě 0

Př. Vypište návratový kód vlákna.

TerminateThread neukončuje korektně vlákna, pro ukončení vlákna jiným by se mělo postupovat takto:

Lokální uložení vlákna

Pomocí lokálního uložení vlákna (TLS) lze vytvořit lokální kopii statických a globálních proměnných vláken.

TlsAlloc
  • vrací TLS index, při chybě 0xFFFFFFFF

TlsSetValue
  • uloží hodnotu na lpTlsValue na místo přístupné přes TLS index dwTlsIndex
  • vrací nenulovou hodnotu, při chybě 0

TlsGetValue
  • vrací hodnotu na pozici určené TLS indexem dwTlsIndex, při chybě 0

TlsFree
  • uvolní TLS index dwTlsIndex
  • vrací nenulovou hodnotu, při chybě 0

Lokální uložení vlákna se používá takto:

PŘÍKLAD

Další funkce týkající se vláken jsou:



Jan Outrata
outrata@phoenix.inf.upol.cz