Thread in UNIX/Linux
Pthreads
Thread
v SummarisingØ Traditionally each thread has a unique flow of
execution, i.e., does one thing at a timeØ To do more things simultaneously inside the same
process, several threads have to be activatedØ The process resources are common to all threads
belonging to the same processØ Since the memory is shared between several
threads, it's necessary to take care of its consistency
Pthreads
v The library POSIX threadsØ POSIX 1003.1c from 1995Ø Reviewd by the IEEE POSIX 1003.1 2004 Edition
v or Pthreads is the standard UNIX library for thread management
v PthreadsØ Is defined for C but it's available also in other
languages (e.g., FORTRAN)Ø Provides threada at user or kernel level
Pthreads
v EssentiallyØ A thread is a program function (procedure) that is
executed independently from the rest of the program
Ø A cocurrent process made of several threads can be seen as a set of functions (procedures) executing independently and that share the process resources
Pthreads
v Pthreads defines more than 60 thread management functions
v Pthreads allows toØ Create and manipulate threadsØ Synchronize threadsØ Protect the resources that are in common between
threadsØ Schedule threadsØ Destroy threads
Pthreads
v All functions have a name of the kind pthread_*v The basic functions are
Ø pthread_equalØ pthread_selfØ pthread_createØ pthread_exitØ pthread_joinØ pthread_cancelØ pthread_detach
Library and compilation
v The Pthread functions are defined in the header fileØ pthreads.h
v It's important to remember toØ Insert into the .c files the row
● #include <pthread.h>Ø Compile the programs using the option or
including the library pthread● gcc –Wall –g –o <exeName> –pthread <file.c>● gcc –Wall –g –o <exeName> <file.c> –lpthread
Thread Identifier
v Every thread is identified by a univocal identifier similar to a process PID (pid_t)
v A thread identifier is of typ pthread_t Ø The identifier is opaque
● Its definition depends on the implementation● Can be accessed/used only through expressly
defined functions in Pthreads● It's not possible to directly compare two identifiers
or to pront their valueØ Has a meaning only inside the process in which
the thread has been executed (while the PID èglobal inside the system)
System call pthread_equal ()
int pthread_equal ( pthread_t tid1, pthread_t tid2,);
v Compares two thread identifiersv Parameters
Ø Two thread identifiersv Return value
Ø Different from 0 if the threads are the sameØ Equal to 0 otherwise
System call pthread_self ()
pthread_t pthread_self ( void);
v Return the thread idenfier of the calling threadv Can be used with pthread_equal to self-identify
a thread (e.g., so that the thread performs a correct access to its personal data)
System call pthread_create ()
int pthread_create ( pthread_t *tid, const pthread_attr_t *attr, void *(*startRoutine)(void *), void *arg );
v At execution, every program includes only a single process and a single thread
v pthread_create generates a new threadØ The number of calls is undefined and depends on
the implemenation
System call pthread_create ()
v ParametersØ Generated thread identifier (tid)Ø Thread's attributes (attr)
● NULL if is a default attributeØ C routine executed by the thread (startRoutine)
int pthread_create ( pthread_t *tid, const pthread_attr_t *attr, void *(*startRoutine)(void *), void *arg );
System call pthread_create ()
Ø Argument (sinle) passed to the starting routine (arg)
● Use NULL if there's no argumentv Return value
Ø Value 0 if successfulØ An error code in case of failure
int pthread_create ( pthread_t *tid, const pthread_attr_t *attr, void *(*startRoutine)(void *), void *arg );
System call pthread_exit ()
v A whole process (with all its threads) terminate ifØ One of its thread performs an exitØ The main performs a returnØ One of its thread receives a signal whose action is
to terminatev A single thread can terminate
Ø Performing a return from its starting function (the returned value is equal to the thread exit code)
Ø Receiving a pthread_cancel from another threadØ Executing a pthread_exit
System call pthread_exit ()
int pthread_exit ( void *valuePtr);
v Allows a thread to terminatev Parameters
Ø The pointer without type (void * valuePtr) èis available to the thread that performs a pthread_join
v Return valueØ Value 0 if successfulØ An error code in case of failure
System call pthread_join ()
v At creation a thread can be declaredØ Joinable
● Another thread can perform a "wait" (pthread_join) on it
Ø Detached● Its termination can't be waited explicitly (isn't
joinable)v A detached thread can't be joined
System call pthread_join ()
v If the threadØ Is joinable its termination state is held until
another thread executed a pthread_join for that thread
Ø Is detached its termination state is immediately released
v The thread that calls the pthread_join remains blocked untile the requested thread performs a pthread_exit
System call pthread_join ()
int pthread_join ( pthread_t tid, void **valuePtr);
v Used by a thread to wait on (wait) another specific thread
pthread_create()
Thread iniziale
Thread iniziale
Worker thread
pthread_join ()
pthread_exit ()
System call pthread_join ()
int pthread_join ( pthread_t tid, void **valuePtr);
v ParametersØ Waited thread identifier (tid)Ø Pointer without type (void **valuePtr) to
● Returned value from the pthread_exit● The value PTHREAD_CANCELED if the thread has
been canceled
System call pthread_join ()
int pthread_join ( pthread_t tid, void **valuePtr);
v Return valueØ Value 0 if successfulØ An error code in case of failure
● If the thread as born in the detached state the pthread_join can fail
● In this case it return the value EINVAL, but the behavior and the value depend on the implementation
System call pthread_cancel ()
int pthread_cancel ( pthread_t tid);
v Termines the pointed thread (it's the same as if the thread executes a pthread_exit)
v ParametersØ Thread indentifier (tid)
v Return valueØ Value 0 if successfulØ An error code in case of failure
System call pthread_detach ()
int pthread_detach ( pthread_t tid);
v Declares the thread tid as detached pointing out that it memory can be returned
v It's not possible to perform a join anymore with this thread
v Essentially future calls to pthread_join fails with en error code (EINVAL o ESRCH)
System call pthread_detach ()
int pthread_detach ( pthread_t tid);
v ParametersØ Thread identifier (tid)
v Return valueØ Value 0 if suffessfulØ An error code in case of failure
Exercise
v Realize with the function pthread_create and pthread_join the following precedence graph
A
F
C
D
B
G
E
Solution
int random_time(int max){ return (int)(rand() % max) + 1;}
int main (void) { pthread_t th_cf, th_e; int *rt; void *retval; srand (getpid()); rt = (int *) malloc (sizeof (int)); *rt = random_time (10); sleep (*rt); printf ("A after %d seconds\n", *rt);
Solution
*rt = random_time (10); pthread_create (&th_cf,NULL,CF,(void *)rt); *rt = random_time (5); sleep (*rt); printf ("B after %d seconds\n", *rt); *rt = random_time (10); pthread_create (&th_e,NULL,E,(void *)rt); *rt = random_time (5); sleep (*rt); printf ("D after %d seconds\n", *rt); pthread_join (th_cf, &retval); pthread_join (th_e, &retval); *rt = random_time (8); sleep (*rt); printf ("G after %d seconds\n", *rt); return 0;}
Solution
static void *CF (void *arg) { int rt, *t = (int *) arg; sleep (*t); printf ( "C after %d seconds\n", *t); rt = random_time (2); sleep (rt); printf ( "F after %d seconds\n", *t); return 0;}static void *E (void *arg) { int *t = (int *) arg; sleep (*t); printf ( "E after %d seconds\n", *t); return 0;}
Exercise
v Realize with the functions pthread_create and pthread_join the following precedence graph
A
E
C
B
I
F
D
H
G
Exercise
v A file an undefined number of charactersv Realize a program with concurrent threads where
three threads (T1, T2, T3) work in pipeline to manage the fileØ T1: Reads from the file a character at a timeØ T2: Trasforms the character read by T1 in
uppercaseØ T3: Prints the character produced by T2 on
standard output
Solution
static void *GET (void *arg) { char *c = (char *) arg; *c = fgetc (fg); return NULL;}static void *UPD (void *arg) { char *c = (char *) arg; *c = toupper (*c); return NULL;}static void *PRINT (void *arg) { char *c = (char *) arg; putchar (*c); return NULL;}
Solution
FILE *fg;char next, this, last;
int main (int argc, char ** argv) { int retC; pthread_t tGet, tUpd, tPrint; void *retV; if ((fg = fopen(argv[1], "r")) == NULL){ perror ("Errore fopen\n"); exit (0); } this = ' '; last = ' '; next = ' ';
Solution
while (next != EOF) { retC = pthread_create (&tGet,NULL,GET,&next); if (retC != 0) fprintf (stderr, ...); retC = pthread_create (&tUpd,NULL,UPD,&this); if (retC != 0) fprintf (stderr, ...); retC = pthread_create (&tPrint,NULL,PRINT,&last); if (retcode != 0) fprintf (stderr, ...); retC = pthread_join (tGet, &retV); if (retC != 0) fprintf (stderr, ...); retC = pthread_join (tUpd, &retV); if (retC != 0) fprintf (stderr, ...); retC = pthread_join (tPrint, &retV); if (retC != 0) fprintf (stderr, ...); last = this; this = next; }
Solution
// Last two chars processing
retC = pthread_create(&tUpd,NULL,UPD,&this); if (retC!=0) fprintf (stderr, ...); retC = pthread_create(&tPrint,NULL,PRINT,&last); if (retC != 0) fprintf (stderr, ...); retC = pthread_join (tUpd, &retV); if (retC != 0) fprintf (stderr, ...); retC = pthread_join (tPrint, &retV); if (retC != 0) fprintf (stderr, ...); retC = pthread_create(&tPrint,NULL,PRINT,&this); if (retC != 0) fprintf (stderr, ...); return 0;}