Ogni SO fornisce al programmatore una libreria di funzioni che permettono ad
un’applicazione utente di utilizzare le risorse messe a disposizione dal
sistema operativo. Questa libreria è denominato API (Application Program Interface ).
Una parte importante dell’API è costituita da quelle funzioni che permettono di creare threads all’interno di un programma.
Prima di illustrare i passi necessari per creare un thread occorre premettere alcune considerazioni.
Un thread è visto da Windows come un “oggetto” facente parte dell’insieme dei cosiddetti oggetti kernel. Gli oggetti kernel sono i processi, i thread, e tutti gli oggetti che gestiscono la comunizazione e la sincronizzazione fra processi o threads.
Un thread si può trovare in due stati: segnalato e non segnalato. Il thread è segnalato se ha terminato, cioè se la funzione che implementa il codice del thread ha effettuato l’istruzione return, non segnalato se è ancora in esecuzione.
Un thread presenta le seguenti importanti proprietà
Viene referenziato da un handle, un numero di 32 bit che lo identifica univocamente all'interno del sistema
Ha un contatore d’uso che all’atto della creazione viene posto a 1 e successivamente aumentato ogni volta che viene creata una nuova istanza dello stesso thread.
Quando termina (cioè fa return) , viene deallocato solo il contatore d'uso è uguale a 0
Per creare uno o più threads occorre:
Scrivere una funzione che contiene il codice di ciascun thread deve eseguire
Creare il thread con la funzione CreateThread
Attendere, chiamando una funzione specifica, la terminazione del thread (cioè che il thread sia segnalato)
Chiudere il thread con la funzione CloseHandle
La
funzione che implementa il codice del thread deve avere la seguente
intestazione :
DWORD WINAPI nome_funzione(LPVOID lpParam){
/* istruzioni */
return (0) ;
}
Per creare un
thread si chiama la funzione CreateThread
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
LpThreadAttributes
= NULL
E’ un puntatore alla struct SECURITY_ATTRIBUTES . Questo parametro ha senso solo in WNT/2000 S, altrimenti ignorato. Metteteci una pietra sopra e ponetelo uguale a NULL
dwStackSize = 0
Specifica in byte la dimensione dello stack da assegnare al thread. Se lo mettete a 0 Windows gli assegna la stessa grandezza dello stack del thread primario
lpStartAddress =
nome della funzione
E’ l’indirizzo del thread (32 bit). Passate il nome che avete dato alla funzione thread
LpParameter
Specifica il puntatore al parametro passato alla funzione thread. Se il thread non ha parametri passate LPVOID(0) o NULL. Il tipo LPVOID permette di passare qualunque tipo di dati alla funzione con il casting
dwCreationFlags
Specifica le modalità di creazione del thread e ha due possibili valori :
0, il thread passa subito nello stato di running dopo la creazione.
CREATE_SUSPENDED il thread non viene eseguito subito, ma viene messo nello stato di waiting , finchè non viene “svegliato” dalla funzione ResumeThread .
lpThreadId
Puntatore all’identificatore del thread. A meno che non lavoriate in WNT/2000S, dovette passare obbligatoriamente l’indirizzo di una variabile. Nel primo caso potete passare NULL.
In caso di successo la funzione ritorna l’handle del thread. Diversamente ritorna NULL
DWORD
ResumeThread(
HANDLE hHandle,
);
hHandle
Handle al thread
La funzione decrementa un conteggio di sospensione del thread . Se il conteggio va a 0 viene rispristinata la sua esecuzione.
Restituisce il conteggio del thread sospeso.
Le funzioni che attendono la terminazione dei threads sono due WaitForSingleObject e WaitForMultipleObjects
La funzione WaitForSingleObject attende che si verifichi uno di questi eventi:
Il thread termina (stato segnalato)
E’ scaduto uno specificato timeout
DWORD
WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
hHandle
L’handle
del thread restituito da CreateThread.
dwMilliseconds
Specifica il tempo di attesa in msec, scaduto il quale la funzione ritorna anche se il thread non ha terminato. Se questo parametro si pone uguale a INFINITE, la funzione ritorna solo se il thread ha terminato la sua esecuzione.
La funzione restituisce i seguenti valori:
WAIT_OBJECT_0:
Il thread ha terminato
WAIT_TIMEOUT: è scaduto il timeout e il thread non ha ancora terminato
La funzione WaitForMultipleObjects attende che si verifichi uno dei seguenti eventi::
Uno dei threads termina
Scade un intervallo di tempo prefissato
DWORD
WaitForMultipleObjects(
DWORD nCount,
CONST HANDLE *lpHandles,
BOOL bWaitAll,
DWORD dwMilliseconds
};
nCount
Specifica il numero di threads nell’array puntato da lpHandles. Il numero massimo è dato dalla costante MAXIMUM_WAIT_OBJECTS.
lpHandles
L’indirizzo
dell’array di threads.
bWaitAll
dwMilliseconds
Specifica il tempo d’attesa, scaduto il quale la funzione ritorna. Se il valore è INFINITE le modalità d’attesa sono determinate da bWaitAll
La funzione restituisce i seguenti valori :
Da
WAIT_OBJECT_0 a (WAIT_OBJECT_0
+ nCount – 1): se bWaitAll
è TRUE indica che tutti i thread hanno terminato. se è
FALSE, il valore di ritorno dà l’indice,
nell’array di threads, del thread che ha terminato. Se più thread hanno
terminato durante la chiamata, l’indice restituito è il più piccolo
WAIT_TIMEOUT: il timeout è scaduto e nessuno dei threads (bWaitAll =TRUE) ha terminato.
La funzione CloseHandle chiude l’handle del thread, decrementando il contatore d’uso di 1. Questo non comporta necessariamente la deallocazione del thread. Il thread viene deallocato solo se ha terminato e il suo contatore d’uso è andato a 0.
BOOL CloseHandle(HANDLE hobject)
hObject
Handle al thread
La funzione restituisce TRUE se tutto è andato bene.