SYSTEMS PROGRAMMING
LECTURE 6
THREADING
THREADS
• A typical UNIX process can be thought of as having
a single thread of control
• With multiples threads we can design programs to
do more than one thing at a time. Benefits:
• Simplify code that deal with asynchronous events
• Easy sharing of memory and file descriptors
• Some problems can be partitioned so that overall
program throughput can be improved
• Interactive program can realise improved
response time
THREADS
• A thread consists of the information necessary to
represent an execution context within a process
• Include thread ID, a set of register values, a
stack, a scheduling priority and policy, a signal
mask, an errno variable and thread-specific
data
• Everything within a process is shareable among
the threads in a process, including the text of the
executable, the program’s global and heap
memory, the stacks and file descriptors
THREAD CREATION
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp,
const pthread_attr_t *restrict attr,
void *(*start_rtn)(void),
void restrict *arg);
Return 0 if OK, error number on failure
• The memory location pointed to by tidp is set to the
thread ID of the newly created thread
• The attr argument is used to customize various thread
attributes (NULL for default)
• New thread starts running at the address of start_fn
THREAD CREATION
• start_rtn takes a single argument, arg, which is
a typeless pointer
• If more than one argument are required, a structure
needs to defined, initialised and passed
• When a thread is created there is no guarantee
which runs first
• The new thread has access to the process address
space and inherits the calling thread’s floating point
environment and signal mask
• The set of pending signals for the thread is cleared
THREAD CREATION
#include <pthread.h>
pthread_t ntid;
void *thr_fn(void *arg)
{
printf(“New threadn”);
return (void *) 0;
}
int main(void)
{
pthread_create(&ntid, NULL, thr_fn, NULL);
printf(“Main threadn”);
exit(0);
}
THREAD TERMINATION
• If any thread within a process calls an exit function
then the entire process terminates
• When the default action is to terminate the process, a
signal sent to a thread will terminate the entire
process
• A single thread can exit in three ways:
• Return from the start routine
• Thread can be cancelled
• Thread calls pthread_exit
THREAD TERMINATION
#include <pthread.h>
void pthread_exit(void *rval_ptr);
int pthread_join(pthread_t thread,
void **rval_ptr);
Return 0 if OK, errno on failure
• When joining, the calling thread will block until the
specified thread call pthread_exit, returns from
its start routine or is cancelled
• If cancelled, memory location of rval_ptr is set to
PTHREAD_CANCELLED
THREAD TERMINATION
#include <pthread.h>
pthread_t ntid; void *tret;
void *thr_fn(void *arg)
{
printf(“New threadn”);
return (void *) 0;
}
int main(void)
{
pthread_create(&ntid, NULL, thr_fn, NULL);
printf(“Main threadn”);
pthread_join(ntid, &tret);
exit(0);
}
THREAD TERMINATION
#include <pthread.h>
void pthread_cancel(pthread_t tid);
Return 0 if OK, errno on failure
int pthread_cleanup_push(
void (*rtn) (void *), void *arg);
void pthread_cleanup_pop(int execute)
• pthead_cancel doesn’t wait for thread to
terminate, it merely make the request
• Threads can choose to ignore the cancel request, or
control how it is cancelled
THREAD TERMINATION
• A thread can arrange for functions to be called
when it exists, similar to atexit functions
• They are known as thread cleanup handlers
• More than one handler can be established for
each thread
• Handlers are recorded in a stack, so they are
executed in reverse order from that with which
they were registered
THREAD DETACHING
#include <pthread.h>
void pthead_detach(pthread_t tid);
Return 0 if OK, errno if failure
• By default a thread’s termination status is retained
until pthread_join is called
• A thread’s underlying storage can be reclaimed
immediately on termination if the thread is
detached
• A call to pthread_join for a detached process
will fail, returning EINVAL
THREAD ATTRIBUTES
• detachstate: detached thread attribute
(joinable or detached)
• guardsize: guard buffer size in bytes at the
end of thread stack
• stackaddr: lowest address of thread stack
• stacksize: size in bytes of thread stack
• Remember: threads share the virtual address
space, where threads’ stack reside
• Default guardsize is PAGESIZE bytes
THREAD SYNCHRONISATION
• When multiple threads share the same memory we
need to make sure that each thread sees a
consistent view of the data
• If each thread uses variables that other threads
don’t read or modify, or variables are readonly,
no consistency problems exist
• When one thread can modify a variable that
other thread can read or modify we need to
synchronise the threads to ensure that they don’t
use an invalid value when accessing the memory’s
content
THREAD SYNCHRONISATION
THREAD SYNCHRONISATION
MUTEXES
• A mutex (mutual exclusion lock) is a lock that we
set (lock) before accessing a shared resource and
release (unlock) when we’re done
• While it is set any other thread that tries to set it
will block until we release it
• If more than one thread is blocked when we
unlock the mutex, then they all will be made
runnable and the first one to run will be able to
set the lock
• Others will see mutex still locked and go back
waiting
MUTEXES
#include <pthread.h>
int ptrhead_mutex_init(
pthread_mutex_t *restrict mutex, const
pthread_mutexattr_t restrict addr);
int pthread_mutex_destroy(
pthread_mutex_t *mutex);
Return 0 if OK, errno on error
• A mutex variable is represented by the
pthread_mutex_t data type
• Mutexes must be initialised by either setting it to the
constant PRTHEAD_MUTEX_INITIALISER (for
static mutexes) or called pthread_mutex_init
MUTEXES
#include <pthread.h>
int pthread_mutex_lock(
pthread_mutex_t *mutex);
int pthread_mutex_trylock(
pthread_mutex_t *mutex);
int pthread_mutex_unlock(
pthread_mutex_t *mutex);
Return 0 if OK, errno on failure
• If thread can’t afford to block for a mutex to become
unlocked, pthread_mutex_trylock can be
used to lock the mutex conditionally
MUTEXES
See thread_mutexes.c
DEADLOCK AVOIDANCE
• A thread will deadlock itself if it tries to lock the
same mutex twice
• There are less obvious ways how deadlock can
occur
• They can be avoided by carefully controlling the
order in which mutexes are locked
• In case of complex program architectures, you
can try using pthread_mutex_lock to
avoid deadlocking
SYNCHRONISATION ATTRIBUTES
• By default, multiple threads can access the same
synchronisation objects (process-shared mutex =
PTHREAD_PROCESS_PRIVATE)
• Mechanism exist which allow independent processes
to map the same extent of memory into their
independent memory space
• If process-shared mutex =
PTHREAD_PROCESS_SHARED, a mutex
allocated from a shared memory extent may be
used for synchronisation by those processes
SYNCHRONISATION ATTRIBUTES
• type mutex attribute controls the characteristics of
the mutex:
• normal – standard mutex that doesn’t do any
special error checking or deadlock detection
• errorcheck – provides error checking
• recursive – allows the same thread to lock it
multiple times without first unlocking it (using
internal lock count)
• default – request default semantics
(implementation specific)
READERWRITER LOCKS
• RW locks allow for higher degrees of parallelism
• Three states are possible: locked in read mode, locked
in write mode, unlocked
• Only one thread at a time can hold a RW lock in write
mode, however multiple thread can hold it in read
mode at the same time
• When write-locked, all threads trying to lock it block
until unlocked
• When in read-mode, all thread trying to lock it in read
mode are given access, however threads attempting to
lock in write mode are blocked
READERWRITER LOCKS
• RW locks usually block additional readers if a
block is already held in read mode and a thread is
blocked trying to acquire it in write mode
• This avoids writer starvation
• RW locks are well suited for situations where data
structures are read more often than they are
modified
• RW are also called shared exclusive locks
• They must be initialised before use and destroyed
before freeing their underlying memory
READERWRITER LOCKS
#include <pthread.h>
int pthread_rw_lock_init(
pthread_rw_lock_t *restrict rwlock,
const pthread_rwlockattr_t attr);
int pthread_rwlock_destroy(
pthread_rwlock_t *rwlock)
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
int pthread_rwlock_tryrdlock(
pthread_rwlock_t *rwlock)
int pthread_rwlock_trywrlock(
pthread_rwlock_t *rwlock)
Return 0 if OK, errno if failure
CONDITION VARIABLES
• Synchronisation mechanism for threads
• Provide a place for threads to rendevouz
• When used with mutexes, condition variables allow
threads to wait in a race-free way for arbitrary
conditions to occur
• A thread must first lock a mutex to change the
condition state
• Other thread won’t notice the change until they
acquire the mutex
• Initialised with PTHREAD_COND_INITIALIZER
CONDITION VARIABLES
#include <pthread.h>
int pthread_cond_init(
pthread_cond_t *restrict cond,
pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(
pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
cont struct timespec *restrict timeout
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
Return 0 if OK, errno on failure
CONDITION VARIABLES
See condition_variables.c
BARRIERS
• Synchronisation mechanism that lets you corral
several cooperating threads, forcing them to
wait at a specific point until all have finished
before any one thread can continue
• Unlike pthread_join, you’re waiting for the
threads to rendevouz at a cerain point
• When the specified number of threads arrive at
a barrier we unlock all of them so they can
continue to run.
BARRIERS
#include <pthread.h>
int pthread_barrier_init(
pthread_barrier_t *barrier,
const pthread_barrierattr_t *attr,
unsigned int count);
int pthread_barrier_destroy(
pthread_barrier_t *barrier);
int pthread_barrier_wait(
pthread_barrier_t *barrier);
Return 0 if OK, errno on error
• count holds the number of thread that must call
pthread_barrier_wait
CONDITION VARIABLES
See barriers.c
THREAD-SPECIFIC DATA
• Also known as thread-private data
• A mechanism for storing and finding data
associated with a particular thread
• Each thread accesses its own separate copy of the
data without worrying about synchronising access
with other threads
• For example, this is useful to redefine errno such
that each thread has it’s own private version
• Except for using registers, there is no way for one
thread to prevent another from accessing its data.
THREAD-SPECIFIC DATA
#include <pthread.h>
int pthread_key_create(pthread_key_t *keyp,
void (*destructor) (void *));
int pthread_key_delete(pthread_key_t *key);
Return 0 if OK, errno on failure
• Before allocating thread-specific data we need to
create a key to associate with the data
• Same key can be used by all threads in the process,
but each thread will associate a different thread-
specific data address with the key
THREAD-SPECIFIC DATA
• pthread_key_create also associates an
optional destructor function with the key
• When thread exits the destructor is called with the
data address as the only argument
• Threads generally use malloc to allocate thread-
specific data, the destructor usually frees the
allocated memory
• When thread exits the destructors are called in an
implementation-defined order
• pthread_key_delete will not invoke the
destructor
THREAD-SPECIFIC DATA
• Depending on how the system schedules threads,
some threads might see one key value, whereas
other threads migh see a different key value
• This race can be solved by using pthread_once
• initflag must be a nonlocal variable and
initialised
#include <pthread.h>
pthread_once_t = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *initflag,
void (*init_routine)(void));
THREAD-SPECIFIC DATA
void destructor(void *)
pthread_key_t key;
pthread_once_t init_done = PTRHEAD_ONCE_INIT;
void thread_init(void)
{
err = pthread_key_create(&key, destructor);
}
int threadfunc(void *arg)
{
pthread_once(&init_done, thread_init);
...
}
THREAD-SPECIFIC DATA
• Once a key is created we can associate thread-
specific data with the key
• Once they are set, we can access the data anytime
#include <pthread.h>
void *pthread_getspecific(pthread_key_t key);
Returns thread-specific data or NULL if no
value has been associated with the key
int pthread_setspecific(pthread_key_t key,
cont void *value);
Return 0 of OK, errno on failure
THREADS AND SIGNALS
• Each thread has its own signal mask, but signal
disposition is shared by all threads in a process
• Individual threads can block signals, but when a
thread modifies the action associated with a signal
all threads share the action
• Signals are delivered to a single thread in the
process
• If the signal is related to a hardware fault or timer
it is sent to the thread whose action caused the
event
• Other signals are delivered arbitrarily
THREADS AND SIGNALS
#include <pthread.h>
int pthread_sigmask(int how,
const sigset_t *restrict set,
sigset_t *restrict oset
int sigwait(const sigset_t *restrict set,
int restrict signop);
int pthread_kill(pthread_t thread, int signo);
Return 0 if OK, errno on failure
• sigprocmask is undefined in a multithreaded
process, so pthread_signals has to be used.
• A thread can wait for one or more signals by calling
sigwait

System Programming - Threading

  • 1.
  • 2.
    THREADS • A typicalUNIX process can be thought of as having a single thread of control • With multiples threads we can design programs to do more than one thing at a time. Benefits: • Simplify code that deal with asynchronous events • Easy sharing of memory and file descriptors • Some problems can be partitioned so that overall program throughput can be improved • Interactive program can realise improved response time
  • 3.
    THREADS • A threadconsists of the information necessary to represent an execution context within a process • Include thread ID, a set of register values, a stack, a scheduling priority and policy, a signal mask, an errno variable and thread-specific data • Everything within a process is shareable among the threads in a process, including the text of the executable, the program’s global and heap memory, the stacks and file descriptors
  • 4.
    THREAD CREATION #include <pthread.h> intpthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void restrict *arg); Return 0 if OK, error number on failure • The memory location pointed to by tidp is set to the thread ID of the newly created thread • The attr argument is used to customize various thread attributes (NULL for default) • New thread starts running at the address of start_fn
  • 5.
    THREAD CREATION • start_rtntakes a single argument, arg, which is a typeless pointer • If more than one argument are required, a structure needs to defined, initialised and passed • When a thread is created there is no guarantee which runs first • The new thread has access to the process address space and inherits the calling thread’s floating point environment and signal mask • The set of pending signals for the thread is cleared
  • 6.
    THREAD CREATION #include <pthread.h> pthread_tntid; void *thr_fn(void *arg) { printf(“New threadn”); return (void *) 0; } int main(void) { pthread_create(&ntid, NULL, thr_fn, NULL); printf(“Main threadn”); exit(0); }
  • 7.
    THREAD TERMINATION • Ifany thread within a process calls an exit function then the entire process terminates • When the default action is to terminate the process, a signal sent to a thread will terminate the entire process • A single thread can exit in three ways: • Return from the start routine • Thread can be cancelled • Thread calls pthread_exit
  • 8.
    THREAD TERMINATION #include <pthread.h> voidpthread_exit(void *rval_ptr); int pthread_join(pthread_t thread, void **rval_ptr); Return 0 if OK, errno on failure • When joining, the calling thread will block until the specified thread call pthread_exit, returns from its start routine or is cancelled • If cancelled, memory location of rval_ptr is set to PTHREAD_CANCELLED
  • 9.
    THREAD TERMINATION #include <pthread.h> pthread_tntid; void *tret; void *thr_fn(void *arg) { printf(“New threadn”); return (void *) 0; } int main(void) { pthread_create(&ntid, NULL, thr_fn, NULL); printf(“Main threadn”); pthread_join(ntid, &tret); exit(0); }
  • 10.
    THREAD TERMINATION #include <pthread.h> voidpthread_cancel(pthread_t tid); Return 0 if OK, errno on failure int pthread_cleanup_push( void (*rtn) (void *), void *arg); void pthread_cleanup_pop(int execute) • pthead_cancel doesn’t wait for thread to terminate, it merely make the request • Threads can choose to ignore the cancel request, or control how it is cancelled
  • 11.
    THREAD TERMINATION • Athread can arrange for functions to be called when it exists, similar to atexit functions • They are known as thread cleanup handlers • More than one handler can be established for each thread • Handlers are recorded in a stack, so they are executed in reverse order from that with which they were registered
  • 12.
    THREAD DETACHING #include <pthread.h> voidpthead_detach(pthread_t tid); Return 0 if OK, errno if failure • By default a thread’s termination status is retained until pthread_join is called • A thread’s underlying storage can be reclaimed immediately on termination if the thread is detached • A call to pthread_join for a detached process will fail, returning EINVAL
  • 13.
    THREAD ATTRIBUTES • detachstate:detached thread attribute (joinable or detached) • guardsize: guard buffer size in bytes at the end of thread stack • stackaddr: lowest address of thread stack • stacksize: size in bytes of thread stack • Remember: threads share the virtual address space, where threads’ stack reside • Default guardsize is PAGESIZE bytes
  • 14.
    THREAD SYNCHRONISATION • Whenmultiple threads share the same memory we need to make sure that each thread sees a consistent view of the data • If each thread uses variables that other threads don’t read or modify, or variables are readonly, no consistency problems exist • When one thread can modify a variable that other thread can read or modify we need to synchronise the threads to ensure that they don’t use an invalid value when accessing the memory’s content
  • 15.
  • 16.
  • 17.
    MUTEXES • A mutex(mutual exclusion lock) is a lock that we set (lock) before accessing a shared resource and release (unlock) when we’re done • While it is set any other thread that tries to set it will block until we release it • If more than one thread is blocked when we unlock the mutex, then they all will be made runnable and the first one to run will be able to set the lock • Others will see mutex still locked and go back waiting
  • 18.
    MUTEXES #include <pthread.h> int ptrhead_mutex_init( pthread_mutex_t*restrict mutex, const pthread_mutexattr_t restrict addr); int pthread_mutex_destroy( pthread_mutex_t *mutex); Return 0 if OK, errno on error • A mutex variable is represented by the pthread_mutex_t data type • Mutexes must be initialised by either setting it to the constant PRTHEAD_MUTEX_INITIALISER (for static mutexes) or called pthread_mutex_init
  • 19.
    MUTEXES #include <pthread.h> int pthread_mutex_lock( pthread_mutex_t*mutex); int pthread_mutex_trylock( pthread_mutex_t *mutex); int pthread_mutex_unlock( pthread_mutex_t *mutex); Return 0 if OK, errno on failure • If thread can’t afford to block for a mutex to become unlocked, pthread_mutex_trylock can be used to lock the mutex conditionally
  • 20.
  • 21.
    DEADLOCK AVOIDANCE • Athread will deadlock itself if it tries to lock the same mutex twice • There are less obvious ways how deadlock can occur • They can be avoided by carefully controlling the order in which mutexes are locked • In case of complex program architectures, you can try using pthread_mutex_lock to avoid deadlocking
  • 22.
    SYNCHRONISATION ATTRIBUTES • Bydefault, multiple threads can access the same synchronisation objects (process-shared mutex = PTHREAD_PROCESS_PRIVATE) • Mechanism exist which allow independent processes to map the same extent of memory into their independent memory space • If process-shared mutex = PTHREAD_PROCESS_SHARED, a mutex allocated from a shared memory extent may be used for synchronisation by those processes
  • 23.
    SYNCHRONISATION ATTRIBUTES • typemutex attribute controls the characteristics of the mutex: • normal – standard mutex that doesn’t do any special error checking or deadlock detection • errorcheck – provides error checking • recursive – allows the same thread to lock it multiple times without first unlocking it (using internal lock count) • default – request default semantics (implementation specific)
  • 24.
    READERWRITER LOCKS • RWlocks allow for higher degrees of parallelism • Three states are possible: locked in read mode, locked in write mode, unlocked • Only one thread at a time can hold a RW lock in write mode, however multiple thread can hold it in read mode at the same time • When write-locked, all threads trying to lock it block until unlocked • When in read-mode, all thread trying to lock it in read mode are given access, however threads attempting to lock in write mode are blocked
  • 25.
    READERWRITER LOCKS • RWlocks usually block additional readers if a block is already held in read mode and a thread is blocked trying to acquire it in write mode • This avoids writer starvation • RW locks are well suited for situations where data structures are read more often than they are modified • RW are also called shared exclusive locks • They must be initialised before use and destroyed before freeing their underlying memory
  • 26.
    READERWRITER LOCKS #include <pthread.h> intpthread_rw_lock_init( pthread_rw_lock_t *restrict rwlock, const pthread_rwlockattr_t attr); int pthread_rwlock_destroy( pthread_rwlock_t *rwlock) int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) int pthread_rwlock_tryrdlock( pthread_rwlock_t *rwlock) int pthread_rwlock_trywrlock( pthread_rwlock_t *rwlock) Return 0 if OK, errno if failure
  • 27.
    CONDITION VARIABLES • Synchronisationmechanism for threads • Provide a place for threads to rendevouz • When used with mutexes, condition variables allow threads to wait in a race-free way for arbitrary conditions to occur • A thread must first lock a mutex to change the condition state • Other thread won’t notice the change until they acquire the mutex • Initialised with PTHREAD_COND_INITIALIZER
  • 28.
    CONDITION VARIABLES #include <pthread.h> intpthread_cond_init( pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr); int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_timedwait( pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cont struct timespec *restrict timeout int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); Return 0 if OK, errno on failure
  • 29.
  • 30.
    BARRIERS • Synchronisation mechanismthat lets you corral several cooperating threads, forcing them to wait at a specific point until all have finished before any one thread can continue • Unlike pthread_join, you’re waiting for the threads to rendevouz at a cerain point • When the specified number of threads arrive at a barrier we unlock all of them so they can continue to run.
  • 31.
    BARRIERS #include <pthread.h> int pthread_barrier_init( pthread_barrier_t*barrier, const pthread_barrierattr_t *attr, unsigned int count); int pthread_barrier_destroy( pthread_barrier_t *barrier); int pthread_barrier_wait( pthread_barrier_t *barrier); Return 0 if OK, errno on error • count holds the number of thread that must call pthread_barrier_wait
  • 32.
  • 33.
    THREAD-SPECIFIC DATA • Alsoknown as thread-private data • A mechanism for storing and finding data associated with a particular thread • Each thread accesses its own separate copy of the data without worrying about synchronising access with other threads • For example, this is useful to redefine errno such that each thread has it’s own private version • Except for using registers, there is no way for one thread to prevent another from accessing its data.
  • 34.
    THREAD-SPECIFIC DATA #include <pthread.h> intpthread_key_create(pthread_key_t *keyp, void (*destructor) (void *)); int pthread_key_delete(pthread_key_t *key); Return 0 if OK, errno on failure • Before allocating thread-specific data we need to create a key to associate with the data • Same key can be used by all threads in the process, but each thread will associate a different thread- specific data address with the key
  • 35.
    THREAD-SPECIFIC DATA • pthread_key_createalso associates an optional destructor function with the key • When thread exits the destructor is called with the data address as the only argument • Threads generally use malloc to allocate thread- specific data, the destructor usually frees the allocated memory • When thread exits the destructors are called in an implementation-defined order • pthread_key_delete will not invoke the destructor
  • 36.
    THREAD-SPECIFIC DATA • Dependingon how the system schedules threads, some threads might see one key value, whereas other threads migh see a different key value • This race can be solved by using pthread_once • initflag must be a nonlocal variable and initialised #include <pthread.h> pthread_once_t = PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *initflag, void (*init_routine)(void));
  • 37.
    THREAD-SPECIFIC DATA void destructor(void*) pthread_key_t key; pthread_once_t init_done = PTRHEAD_ONCE_INIT; void thread_init(void) { err = pthread_key_create(&key, destructor); } int threadfunc(void *arg) { pthread_once(&init_done, thread_init); ... }
  • 38.
    THREAD-SPECIFIC DATA • Oncea key is created we can associate thread- specific data with the key • Once they are set, we can access the data anytime #include <pthread.h> void *pthread_getspecific(pthread_key_t key); Returns thread-specific data or NULL if no value has been associated with the key int pthread_setspecific(pthread_key_t key, cont void *value); Return 0 of OK, errno on failure
  • 39.
    THREADS AND SIGNALS •Each thread has its own signal mask, but signal disposition is shared by all threads in a process • Individual threads can block signals, but when a thread modifies the action associated with a signal all threads share the action • Signals are delivered to a single thread in the process • If the signal is related to a hardware fault or timer it is sent to the thread whose action caused the event • Other signals are delivered arbitrarily
  • 40.
    THREADS AND SIGNALS #include<pthread.h> int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset int sigwait(const sigset_t *restrict set, int restrict signop); int pthread_kill(pthread_t thread, int signo); Return 0 if OK, errno on failure • sigprocmask is undefined in a multithreaded process, so pthread_signals has to be used. • A thread can wait for one or more signals by calling sigwait