Unix-Linux 5
Threads
Thread
· distinct sequence of execution steps performed within a process
· processes that handle multiple independent tasks benefit from multiple threads
· each thread in a process executes independently and asynchronously
· thread scheduling algorithm
o priority-based
o preemptive
o non-time slicing
· architecture
o each thread requires it own
§ stack
§ register set
§ program counter
§ thread-specific data
§ thread-local variables
§ thread-specific signal massk
§ state information
o all threads in a process share the same
§ address space
§ general signal handling
§ virtual memory
§ common data
§ I/O information, e.g., open files, etc.
· user-level threads
o user-level API – libraries & thread wrapper code
o share resources with other threads within their process space on a single processor
o operating system provides runtime system which manages thread activities
· kernel-level threads
o operating system contains system-level code for each specified thread function
o supports parallelism with multiple threads running on multiple processors
· composite -- mapping user-level threads to kernel-level threads
o one-to-one windows NT, OS/2
o many-to-one
o many-to-many
§ multiple user-level threads
§ pool of kernel-level threads run as
¨ LWP lightweight processes
¨ scheduled & maintained by the operating system
· Thread Libraries
o Mach C-threads
o POSIX Pthreads
o Sun Thread Library Unix International
POSIX Pthreads
· widespread POSIX Compliance
Basic Thread Management
Program Format
#define _REENTRANT
#include <pthread.h
#include <stdio.h
$ cc demo.c –D_POSIX_C_SOURCE –lpthread
int pthread_create ( pthread_t *new_thread_ID, const pthread_attr_r *attr,
void *(*start_func)(void *), void *arg);
void pthread_exit (void *status);
int pthread_join( pthread_t target_thread, void **status);
· a thread should be joined by only one other thread
· if the thread issuing the join is cancelled,
the target thread can be joined by another thread
· if the targeted thread has terminated prior to the issuance of the pthread_join( ) call, it will return immediately and will not block
· a non-detached thread that is not joined, will not release its resources until the process terminates
int pthread_detach( pthread_t threaded);
· when a detached thread finishes, its resources are automatically returned to the system
Command Line Thread Creation Gray – Linux page 338
#define MAX 5
#define TRAND (limit, n)
{
struct timeval t: \
gettimeofday (&t, (void * )NULL); \
(n) = rand_r ((unsigned *) &t.tv_usec) % (limit) + 1;
}
void * say_it (void *);
int main(int argc, char * argv[ ])
{
int i;
pthread_t thread_id[MAX]
int status, *p_status = status;
if ( argc > MAX + 1 )
fprintf(stderr, “%s arg1, arg2, … , arg%d\n”, *argv, MAX), exit(1);
printf(“Displaying \n”);
for ( i = 0; i < argc – 1; ++i)
{
if ( pthread_create( &thread_id[ i ], NULL, say_it, (void *) argv[ i + 1 ]) > 0)
fprintf( stderr, “pthread_create failure\n”), exit(2);
}
for ( i = 0; i < argc – 1; ++i)
{
if ( pthread_join( &thread_id[ i ], (void **) p_status) > 0)
fprintf( stderr, “pthread_join failure\n”), exit(\3);
printf(“Thread %d returns %d”, thread_id[ i ], status);
}
printf(“\nDone\n”);
exit( 0 );
}
void say_it (void *word)
{
int i, numb;
TRAND (MAX, numb);
printf(“\n%d %s “, numb, word);
for ( i = 0; i < numb, ++i ) { sleep( 1 ); printf( “%s “, word ); }
return (void * ) NULL;
}
Thread Attributes
int pthread_attr_init( pthread_attr_r *attr );
· initializes the referenced attribute object
· returns 0 è successful call
· returns 12 (ENOMEM) è insufficient memory space to initialize attribute object
· after initialization, attribute object may be modified
· after modification of the attributes, a thread may be created having those attributes
· thread created before the attribute modifications are not reflected in those threads
Thread Attribute Default Values
Attribute / Default / Commentscontentionscope / PTHREAD_SCOPE_PROCESS / competes for resources within the process; threads are unbound, i.e., not tied to a specific LWP
detachstate / PTHREAD_CREATE_JOINABLE / thread can be joined by other threads; resources are not freed until a call is made to pthread_join or the calling process terminates
stackaddr / NULL / operating system allocates the stack
stacksize / NULL / o/s default; thread stacks do not grow dynamically
priority / – / Inherits the priority of the calling thread
policy / SCHED_OTHER / Scheduling is determined by the o/s
Inheritsched / PTHREAD_EXPLICIT_SCHED / Scheduling policy is explicitly determined by the attribute object
Thread Attribute Get (Accessor) & Set (Mutator)
Attribute / System Calls / Defined Constantscontentionscope / int pthread_attr_setscope
( pthread_attr_t *attr,
int contentionscope); / PTHREAD_SCOPE_PROCESS
Scope within the process
PTHREAD_SCOPE_SYSTEM
Scope throughout the system
int pthread_attr_getscope
( const pthread_attr_t *attr,
int contentionscope);
detachstate / int pthread_attr_setdetachstate
(pthread_attr_t *attr, int *detachstate); / PTHREAD_CREATE_JOINABLE
PTHREAD_CREATE_DETACHED
int pthread_attr_getdetachstate
(const pthread_attr_t *attr,
int *detachstate);
stackaddr / int pthread_attr_setstackaddr
( const pthread_attr_t *attr,
void *stackaddr ); / NULL
nnn i.e., VALID ADDRESS>
int pthread_attr_getstackaddr
( const pthread_attr_t *attr,
void **stackaddr );
stacksize / int pthread_attr_setstacksize
( pthread_attr_t *attr,
size_t *stacksize ); / NULL
nnn <i.e., VALID ADDRESS>
int pthread_attr_getstacksize
( const pthread_attr_t *attr,
size_t *stacksize );
priority / int pthread_attr_setschedparam
( pthread_attr_t *attr,
const struct sched_param *param); / NULL
Reference to a valid sched_param structure with the sched_priority member assigned a valid priority; see <sched.h> included with <pthread.h
int pthread_attr_getschedparam
( pthread_attr_t *attr,
const struct sched_param *param);
policy / int pthread_attr_setschedpolicy
( pthread_attr_t *attr, int policy); / SCHED_OTHER
SCHED_FIFO
SCHED_RR
int pthread_attr_getschedpolicy
( pthread_attr_t *attr, int *policy);
inheritsched / int pthread_attr_setinheritsched
( pthread_attr_t *attr, int inheritsched); / PTHREAD_EXPLICIT_SCHED
int pthread_attr_getinheritsched
( pthread_attr_t *attr, int *inheritsched);
Command Line Detached Thread Creation Gray – Linux page 346
#define MAX 5
#define TRAND (limit, n)
{
struct timeval t: \
gettimeofday (&t, (void * )NULL); \
(n) = rand_r ((unsigned *) &t.tv_usec) % (limit) + 1;
}
void * say_it (void *);
int main(int argc, char * argv[ ])
{
int i;
pthread_t thread_id[MAX]
int status, *p_status = &status;
pthread_attr_t attr_obj;
if ( argc > MAX + 1 )
fprintf(stderr, “%s arg1, arg2, … , arg8\n”, *argv ), exit(1);
printf(“Displaying \n”);
pthread_attr_init ( &attr_obj );
pthread_attr_setdetachedstate ( &attr_obj, PTHREAD_CREATE_DETACHED );
for ( i = 0; i < argc – 1; ++i)
{
if ( pthread_create( &thread_id[ i ], NULL, say_it, (void *) argv[ i + 1 ]) > 0)
fprintf( stderr, “pthread_create failure\n”), exit(2);
}
for ( i = 0; i < argc – 1; ++i)
{
if ( pthread_join( &thread_id[ i ], (void **) p_status) > 0)
fprintf( stderr, “pthread_join failure\n”), exit(\3);
printf(“Thread %d returns %d”, thread_id[ i ], status);
}
printf(“\nDone\n”);
exit( 0 );
}
void say_it (void *word)
{
int i, numb;
TRAND (MAX, numb);
printf(“\n%d %s “, numb, word);
for ( i = 0; i < numb, ++i ) { sleep( 1 ); printf( “%s “, word ); }
return (void * ) NULL;
}
Scheduling Threads
· preemption is the standard assumption
· bound threads – one-to-one, bijective mapping to a particular LWP
o scheduling is determined by the lernel scheduling algorithms, i.e., global scheduling
· unbound threads – thread library determines which LWP will be used
o threads activity is indirectly affected by the kernel scheduling algorithm for LWP
Thread State Diagram
POSIX Thread Scheduling Protocols
· bound versus unbound
o pthread_attr_setscope library call sets the contentionscope attribute values
§ PTHREAD_SCOPE_SYSTEM – thread is mapped one-to-one to a LWP
§ PTHREAD_SCOPE_PROCESS – thread contends with other threads within the process for access to the system resources via a LWP, obtained from the LWP pool; does NOT determine the procedure by which the LWP will be chosen by libpthread
· scheduling policy
o SCHED_OTHER
§ usually the default policy, may vary depending upon the installation
§ normally a time-sharing policy with time slice sizes are assigned according to thread priority
§ order of unblocking waiting threads is not guaranteed
SCHED_FIFO
o SCHED_RR
· Priority
o higher priority threads are scheduled before lower priority threads
o unless changed, the priority of a thread is inherited from its creating thread
o thread priority can be changed at creation time by modifying the thread attribute object before the thread is created
Threads & Signals
· synchronous signal
o caused by a particular threads actions
o signal passed to the thread that generated the exception
§ SIGFPE – divide by zero
§ SIGSEGV – address violation
§ SIGPIPE – broken pipe
§ synchronous pthread_kill system call
· asynchronous signal
o signal not related to any particular threads activity
o selection of which thread to assign the task of handling the signal depends upon the signal mask configurations for all of the threads in the process
o if more than one thread has not blocked reception for that particular signal, there is no guarantee as to which thread will receive the signal
Gray Code Unix page 354
/*compile command: $cc p11.2.c –o p11.2 -lpthread –D_POSIX_PTHREAD_SEMANTICS*/
#define _REENTRANT
#include <pthread.h
#include <stdio.h
#include signal.h
#include stdlib.h
#define MAX 8
void trapper( int );
int main( int argc, char * argv[ ] )
{
sigset_t my_sigs;
int i = 0, sig_in;
if( argc > 1 & argc < MAX + 1 )
{
sigemptyset(my_sigs);
while ( argc-- > 1) sigaddset(&my_sigs, atoi(argv[argc]));
}
else
{
fprintf(stderr, “%s SIG1 … SIG%d\n”, *argv, MAX );
exit( 1 );
}
for( I = 1; i < NSIG; ++i ) sigset( i, trapper ); // trap all signals
pthread_sigmask( SIG_BLOCK, &my_sigs, NULL );
pthread_sigmask( 0, NULL, &my_sigs ); // obtain signal mask
printf(“\nSignal bits turned on\n”);
for ( i = 0; i < NSIG; ++i ) putchar( sigismember(&my_sigs, i ) == 0 ? ‘0’ : ‘1‘ );
printf(“\nWaiting for signals\n”);
i = 0;
while ( i++ < 3 )
{
if ( ( sig_in = sigwait( &my_sigs, &sig_in ) ) != -1 )
printf( “Received signal %d in mask\n”, sig_in );
else
printf( “Received signal is NOT in mask\n” );
}
return 0;
}
void trapper( int s ) printf(“\nIncoming signal %d\n”, s );
Thread Synchronization
· thread mutex limited to a process, i.e., intra-process mutex is global to the process, i.e., it is visible to all threads in the process
· thread mutexes – it is possible for a thread to unlock a mutex which was locked by another thread in the process
· if threads in multiple processes are to be coordinated,
the inter-process mutex must be mapped to shared memory
· mutex declaration
declared & set to 0, i.e., unlocked
static pthread_mutex_t my_lock1;
or
pthread_mutex_t *my_lock2;
my_lock2 = (pthread_mutex_t *) calloc(1, sizeof(pthread_mutex_t));
or
pthread_mutex_t my_lock3 = PTHREAD_MUTEX_INITIALIZER
· mutex attributes
o create attribute
int pthread_mutexattr_init ( pthread_mutexattr_t *attr);
o modify attribute
int pthread_mutexattr_setpshared ( pthread_mutexattr_t *attr,
int process-shared);
PTHREAD_PROCESS_PRIVATE – private to process
PTHREAD_PROCESS_SHARED – shared between processes
· initialize mutex
int pthread_mutex_init ( pthread_mutex_t *mp,
const pthread_mutexattr_t *attr);
· mutex operations
int pthread_mutex_lock( pthread_mutex_t *mp);
if resource is already locked, causes requesting thread to block
lock issued again by thread that has the resource already lock causes a deadlock
int pthread_mutex_unlock( pthread_mutex_t *mp);
if request is made by thread other than the locking thread, results are unspecified
int pthread_mutex_trylock( pthread_mutex_t *mp);
if resource is already locked, requesting thread does not block
int pthread_mutex_destroy( pthread_mutex_t *mp);
uninitializes the mutex, but it must still be explicitly deallocated
Condition Variables
· a particular condition variable is associated with a specific mutex
· coordinate thread activities by using the current value of the critical data protected by the mutex
· thread uses a condition variable to either notify other cooperating threads that the condition has been met, or to block and wait for receipt of the notification
· when a thread blocks on a condition variable, it atomically releases the associated mutex, thus allowing other threads access to the mutex
· condition variable declaration
declared & set to 0, i.e., unlocked
static pthread_cond_t my_lock1;
or
pthread_cond_t *my_lock2;
my_lock2 = (pthread_cond_t *) calloc(1, sizeof(pthread_cond_t));
or
pthread_cond_t my_lock3 = PTHREAD_COND_INITIALIZER
· condition variable operations
int pthread_cond_signal (pthread_cond_t *cond);
one thread unblocked
int pthread_cond_broadcast (pthread_cond_t *cond);
all blocked threads are unblocked
int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait (pthread_cond_t *cond,
pthread_mutex_t *mutex, const struct timespec *abstime);
Multithreaded Semaphores
Thread-Specific Data
· TSD is held by a thread specific pointer and a key
· key allocation
int pthread_key_create( pthread_key_t *keyp,
void (*destructor) (void *value));