Top Banner
CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)
21

CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Dec 13, 2015

Download

Documents

Clara Bradley
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

CSC 552.201 - Advanced Unix Programming, Fall, 2008

Monday, November 24POSIX threads (pthreads)

Page 2: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Pthread system calls, Table 12.1

• pthread_create creates a thread• pthread_join waits for another thread• pthread_self gets this thread’s ID• pthread_equal tests 2 threads for equality• pthread_detach makes caller a daemon

thread; no pthread_join required for cleanup• pthread_exit exits just this thread

• Returning from thread startup function has same effect

Page 3: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Pthread system calls continued

• pthread_kill sends a signal to a thread• pthread_cancel terminates another thread• Signal delivery to threads after pthread_create

• The signal mask is inherited from the creating thread.• The set of signals pending for the new thread is empty.• A new signal can be delivered to any unmasked thread!

• pthread_sigmask sets a thread’s signal mask• Guideline: Use pthread_sigmask to keep child threads from

handling signals. See next slide for the main thread.

Page 4: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Keeping threads safe from signals

• 1. Temporarily block signals in initial thread if ((sigfillset(&maskblock)== -1) || (sigprocmask(SIG_SETMASK, &maskblock, &maskold) == -1))

• 2. pthread_create child thread(s)• The signal mask is inherited from the creating thread.

• 3. The main thread can restore its masksigprocmask(SIG_SETMASK, &maskold, NULL);

Page 5: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

pthread_*() errors don’t set errno

• You cannot report these errors using perror()• strerror() can format a return error code, but

it is not thread safe – it uses a static buffer• ~parson/UnixSysProg/threadwait/strerror_r.c

expands the textbook’s thread-safe functions• They use a mutex and signal masks to protect the

invoking thread.• My enhancements report some additional errors.• See example usage in threadwait.cxx.

Page 6: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

pthread_create parameters

• int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg);

• The start_routine takes a void * parameter that is passed as the pthread_create arg parameter.

• The start_routine return value or pthread_exit parameter gives the thread’s exit status as a pointer to an application object, or a (void *) int.

Page 7: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

pthread attributes

• When pthread_create’s pthread_attr_t attr parameter is non-NULL, it sets thread attributes.

• Joinable versus detached (daemon) state. Former needs a pthread_join call to clean up its resources.

• Stack size and stack guard size.• Thread scheduling policy – FIFO (preemption by priority,

preempted go at queue front), round robin (additional periodic preemption, at queue back), sporadic, with a scheduling priority.

• Inter-process versus intra-process scheduling contention scope.• Attributes are set with dedicated POSIX functions.• There are O.S. specific extensions, e.g., hardware thread pinning.

Page 8: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

~parson/UnixSysProg/threadwait/• if (((errcode = pthread_attr_init(&pattr)) != 0) || ((errcode = pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED)) != 0) || ((errcode = pthread_attr_setschedpolicy(&pattr, SCHED_FIFO)) != 0)) { // by priority and THEN by FIFO order DUMPERR("producer attribute error"); exit(errcode);} if (((errcode = pthread_attr_init(&cattr)) != 0) || ((errcode = pthread_attr_setdetachstate(&cattr, PTHREAD_CREATE_JOINABLE)) != 0) || ((errcode = pthread_attr_setschedpolicy(&cattr, SCHED_RR)) != 0)) { // time-sliced round robin by priority DUMPERR("producer attribute error"); exit(errcode); }

Page 9: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Thread local data

• int pthread_key_create(pthread_key_t *key, void (*destructor, void*));

• This function creates a thread-specific data key visible to all threads in the process. Key values provided by pthread_key_create() are opaque objects used to locate thread-specific data. Although the same key value may be used by different threads, the values bound to the key by pthread_setspecific() are maintained on a per-thread basis and persist for the life of the calling thread. Destructor may be NULL. If not, it is called for the key’s value upon thread exit.

• The key acts like a hash index to access thread-local data.

Page 10: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Thread local data access

• int pthread_setspecific(pthread_key_t key, const void *value);

• Sets thread-local data for key to pointer value.• value points to a valid object that persists across calls.

• void *pthread_getspecific(pthread_key_t key);• Returns the key’s value in this thread, or NULL if they

key has not been set in this thread.

• int pthread_key_delete(pthread_key_t key);• Deletes the mapping in this thread.

• Used for identical functions in multiple threads.

Page 11: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

A mutex encloses a critical section for mutual exclusion.

• A properly used mutex serializes access to inter-dependent data among multiple threads.

• pthread_mutex_init(&buffermutex, NULL);• pthread_mutex_lock() … pthread_mutex_unlock()

• Data access must occur in bounded time.• Second, pthread_mutexattr_t parameter is preset

using pthread_mutexattr_init.• pthread_mutex_trylock is a non-blocking locker.• Mutex is freed using pthread_mutex_destroy.

Page 12: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Mutex attributes (all return int)

• pthread_mutexattr_init(pthread_mutexattr_t *attr);• pthread_mutexattr_destroy(pthread_mutexattr_t

*attr)• pthread_mutexattr_gettype(pthread_mutexattr_t

*restrict attr, int *restrict type);• type PTHREAD_MUTEX_NORMAL – no deadlock

detection, non-recursive (granted once per thread)• PTHREAD_MUTEX_RECURSIVE allows one thread to

lock It multiple times. Unlock calls must balance locks.• PTHREAD_MUTEX_DEFAULT is a risky gamble.

Page 13: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Thread-unsafe static initialization

• The following code is not multithread safe. Why?

static int firsttime = 1 ;...if (firsttime) {

do some initialization stepsfirsttime = 0 ;

}

Page 14: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Thread-safe static initialization

• The following code is multithread safe. It runs at most one time.

static pthread_once_t firsttime = PTHREAD_ONCE_INIT ;

static void init(void) { initialization steps … }…int status = pthread_once(&firsttime, init);

Page 15: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Condition variables

• A condition variable allows a thread to release a mutex temporarily while waiting for a condition on data.

• The waiting thread is awakened and it reacquires the mutex in one atomic step.

• The awakened thread must still recheck the data condition after reacquiring the mutex, since another such thread may have already changed the data condition.

Page 16: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

pthread_cond_init()

• pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr)

• The attr is for shared condvars in shared memory.• Use NULL in single process thread synchronization.

• pthread_cond_destroy destroys a condition var.• pthread_cond_wait and pthread_cond_timedwait

• These wait to be signaled.

• pthread_cond_signal and pthread_cond_broadcast• The signal one waiting thread or all waiting threads respectively.

Page 17: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Pthread read-write locks

• Read/write locks enable multiple readers or one writer to lock a critical section

• int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);• int pthread_rwlock_destroy(pthread_rwlock_t

**rwlock);

• pthread_rwlock_rdlock(), pthread_rwlock_tryrdlock• pthread_rwlock_wrlock()• pthread_rwlock_unlock()

Page 18: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

pthread_rwlock_rdlock() pthread_rwlock_tryrdlock()

• Multiple readers can acquire the lock if no writer holds the lock.

• “POSIX states that it is up to the implementation whether to allow a reader to acquire a lock if writers are blocked on the lock.”

• Solaris man page says, “The calling thread does not acquire the lock if a writer holds the lock or if writers of higher or equal priority are blocked on the lock; otherwise, the calling thread acquires the lock. If the read lock is not acquired, the calling thread blocks until it can acquire the lock.

Page 19: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

pthread_rwlock_wrlock pthread_rwlock_trywrlock

• Pthread_rwlock_wrlock• The calling thread acquires the write lock if no other

thread (reader or writer) holds the read-write lock rwlock. Otherwise, the thread blocks until it can acquire the lock.• Writers are favored over readers of the same priority

to avoid writer starvation.

• Pthread_rwlock_trywrlock• The function fails if any thread currently holds rwlock

(for reading or writing).

Page 20: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

POSIX:SEM semaphores

• sem_t *sem_open(const char *name, int oflag, …);• optional permissions and initial value for O_CREATE

• int sem_init(sem_t *sem, int pshared, unsigned int value); ALSO int sem_destroy(sem_t *sem);

• pshared is 0 for single process, 1 for interprocess• value is 0 for a locked semaphore, > 0 for unlocked

• int sem_wait(sem_t *sem);• blocks on a 0 sem_t value, decrements if > 0• or int sem_trywait(sem_t *sem);

• int sem_post(sem_t *sem);• Adds 1 to sem_t if there are no blocked sem_wait callers, unblocks

one thread if 1 or more are blocked

Page 21: CSC 552.201 - Advanced Unix Programming, Fall, 2008 Monday, November 24 POSIX threads (pthreads)

Programming assignment 4(modify a copy of assignment 2 or 3)

• Each chess plugin starts one or more threads to monitor its incoming data streams, blocking on read(), and copying the data stream to a log file and, for gnuchess, to an output stream.

• Threads reading stdout from gnuchess or pchess must detect moves as in assignment 2.

• They invoke a callback function that passes the move back to the main thread via a condition variable and a queue of moves. The main thread blocks on this condition variable. There is no select() or poll() loop.

• Move injection from the main thread to the stdin on a child game (gnuchess or pchess) must use a mutex to protect writing into the child’s stdin stream, only if there are multiple writers (e.g., xboard to gnuchess).

• Callbacks signal end-of-file and errors in the child data connections.• The main thread must handle signals as in assignment 2. The child threads

must mask out all signals.