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)

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

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.