Piccola Guida alle chiamate di sistema **nix
(Quello che serve per il corso)
Questa pagina fa il paio con quella dedicata alle api di Window$. Le informazioni contenute in essa provengono in gran parte dalle manpages presenti di default in ogni distribuzione GNU/Linux decente e sono, per quanto possibile, state verificate con qualche esperimento sulle mie macchine. Per ulteriori approfondimenti potete consultare le manpages.
Gestione dei processi
...
Gestione dei Thread (si legge thréd, con la "e", non thrid con la "i")
La libreria pthread
Un thread è un flusso di esecuzione all'interno di un processo. Ogni thread contiene una
quantità minima di informazioni di stato; normalmente solo lo stato della CPU ed una maschera
per i segnali. Tutte le altre informazioni sullo stato del processo (quali ad esempio la memoria, i descrittori
dei file) sono condivise tra tutti i thread all'interno dello stesso processo.
NB: Per utilizzare il supporto pthread occorre richiedere al linker l'inclusione della libreria. Quindi ad es.
file: prova_thread.c
#include <pthread.h>
...
int main()
{
...
}
[n4rc0s@maggie so]$ gcc -lpthread prova_thread.c
pthread_create
crea un nuovo thread
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
La funzione pthread_create() crea all'interno del processo un nuovo thread, con gli attributi specificati da attr. Se attr é NULL, vengono utilizzati gli attributi di default. Se non si verificano errori l'ID del thread appena creato viene salvato nella locazione indirizzata dal parametro thread. Il thread viene creato mandando in esecuzione la funzione start_routine con l'unico parametro arg. Se la funzione start_routing ritorna l'effetto sarà analogo a quello di una chiamata esplicita a pthread_exit().
pthread_exit
termina il thread corrente
pthread_exit(void *value_ptr);
Questa funzione viene chiamata implicitamente al termine dell'esecuzione della funzione start_routine specificata in fase della creazione del thread figlio. In generale quindi non è necessario utilizzarla, se non nei casi in cui è necessario anticipare l'interruzione dell'esecuzione del thread.
pthread_join
attende la terminazione di un thread
int pthread_join(pthread_t thread, void **value_ptr);
pthread_t thread
la struttura che contiene le informazioni relative al thread.
void **value_ptr
puntatore utilizzato per la restituzione del valore di ritorno del thread.
Questa funzione sospenderà l'esecuzione del thread chiamante fino a quando il thread specificato termina, a meno che
questo non sia già terminato. Se non vi sono errori e viene specificato un puntatore non-NULL, viene restituito attraverso questo riferimento il valore passato a pthread_exit() dal thread terminante. Evitate chiamate multiple a pthread_join() riferite allo stesso thread.
una piccola demo
/* Una piccola dimostrazione sulla creazione, sincronizzazione e terminazione
dei thread utilizzando la libreria **nix pthread.
*/
#include <pthread.h>
#include <stdio.h>
void my_func
(void)
{
int i;
int somma=
0;
int prodotto=
1;
for (i=
1;i<=
10;i++
) {
somma += i;
prodotto *= i;
}
printf("somma = %d\nprodotto = %d\n", somma, prodotto
);
/* la chiamata a pthread_exit() é _implicita_ */
puts
("Uscita dal thread figlio...");
}
main
()
{
pthread_t thread;
/* crea il nuovo thread, destinato ad eseguire la funzione my_func */
puts
("Creazione del thread...");
if (!pthread_create
( &thread,
NULL, my_func,
NULL )) {
/* pthread_create restituisce 0 se non ci sono stati errori nella creazione
del thread
*/
/* pthread_join attende la terminazione del thread figlio. */
puts
("Attesa del thread...");
pthread_join
( thread,
NULL );
}
puts
("Fine :-)");
return 0;
}
Gestione dei Mutex
Le funzioni dedicate alla gestione dei mutex sono anch'esse all'interno della libreria pthread.
pthread_mutex_init
inizializza il mutex specificato
La funzione pthread_mutex_init() inizializza il mutex referenziato dal parametro
mutex con gli attributi specificati dal parametro
attr. If
attr é NULL, vengono utilizzati gli attributi di default. In assenza di errori il mutex viene inizializzato ed impostato a
sbloccato.
pthread_mutex_destroy
distrugge il mutex
int pthread_mutex_destroy(pthread_mutex_t *mutex);
L'oggetto mutex viene deinizializzato e distrutto, un mutex distrutto può essere reinizializzato. Qualsiasi altra operazione non é definita.
Tentare di distruggere un mutex bloccato
non é una buona idea!
pthread_mutex_lock
blocca il mutex (bloccante)
int pthread_mutex_lock(pthread_mutex_t *mutex);
I mutex vanno acquisiti utilizzando pthread_mutex_lock(). Se il mutex é già bloccato, il thread chiamante si bloccherà fino a quando il mutex diviene nuovamente il mutex diviene nuovamente disponibile. Questa operazione ritornerà con l'oggetto mutex in stato bloccato, posseduto dal thread chiamante.
pthread_mutex_trylock
blocca il mutex (non bloccante)
int pthread_mutex_trylock(pthread_mutex_t *mutex);
Le funzioni pthread_mutex_lock() e pthread_mutex_trylock() sono equivalenti con l'eccezione che se il mutex specificato è già bloccato, pthread_mutex_lock() blocca il thread chiamante e attende che il mutex divenga disponibile, mentre pthread_mutex_trylock() ritorna immediatamente con un valore non nullo (errore).
pthread_mutex_unlock
rilascia il mutex
int pthread_mutex_unlock(pthread_mutex_t *mutex);
La funzione pthread_mutex_unlock() rilascia il mutex specificato dal parametro mutex. Se vi sono thread bloccati in attesa di acquisire il mutex, la policy di schedulazione determinerà quale thread dovra acquisire il mutex.
un semplice esempio che non fa nulla di particolarmente utile...
/* Una piccola dimostrazione sulla creazione, sincronizzazione e terminazione
dei thread utilizzando la libreria **nix pthread. Con l'aggiunta di un mutex
*/
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
/* globale */
pthread_mutex_t mutex;
void my_func
(void)
{
int i;
int somma=
0;
int prodotto=
1;
puts
("Acquisizione del mutex...");
pthread_mutex_lock
( &mutex
);
for (i=
1;i<=
10;i++
) {
somma += i;
prodotto *= i;
}
printf("somma = %d\nprodotto = %d\n", somma, prodotto
);
/* non é necessaria, ma logicamente corretta */
pthread_mutex_unlock
( &mutex
);
/* la chiamata a pthread_exit() é _implicita_ */
puts
("Uscita dal thread figlio...");
}
main
()
{
pthread_t thread;
/* inizializza il mutex per la sincronizazione dei thread. */
puts
("Inizializza e acquisisce il mutex");
pthread_mutex_init
( &mutex,
NULL );
pthread_mutex_lock
( &mutex
);
/* crea il nuovo thread, destinato ad eseguire la funzione my_func */
puts
("Creazione del thread...");
if (!pthread_create
( &thread,
NULL, my_func,
NULL )) {
/* pthread_create restituisce 0 se non ci sono stati errori nella creazione
del thread
*/
/* fa qualcosa per 3 sec. poi rilascia il mutex */
sleep
( 3 );
pthread_mutex_unlock
( &mutex
);
/* pthread_join attende la terminazione del thread figlio. */
puts
("Attesa del thread...");
pthread_join
( thread,
NULL );
}
puts
("Fine :-)");
return 0;
}
There are 2 comments on this page. [Visualizza commenti]