Distinct Sequence of Execution Steps Performed Within a Process

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

non-time slicing

·  architecture

each thread requires it own

§  stack

§  register set

§  program counter

§  thread-specific data

§  thread-local variables

§  thread-specific signal massk

§  state information

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

user-level API – libraries & thread wrapper code

share resources with other threads within their process space on a single processor

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 / Comments
contentionscope / 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 Constants
contentionscope / 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));