37
Multi-core Programming Programming with Posix Threads

Multi-core Programming

  • Upload
    werner

  • View
    66

  • Download
    0

Embed Size (px)

DESCRIPTION

Multi-core Programming. Programming with Posix Threads. Topics. Explore Pthreads “core” functions to create and synchronize threads Compare Pthreads with Win32 threading API. What is Pthreads?. POSIX standard for threads programming interface (1995) - PowerPoint PPT Presentation

Citation preview

Page 1: Multi-core Programming

Multi-core Programming

Programming with Posix Threads

Page 2: Multi-core Programming

Basics of VTune™ Performance Analyzer

2

Topics

• Explore Pthreads “core” functions to create and synchronize threads

• Compare Pthreads with Win32 threading API

Page 3: Multi-core Programming

Programming with POSIX* Threads 3

What is Pthreads?• POSIX standard for threads programming interface (1995)• Implementations of POSIX standard are referred to as POSIX threads

or Pthreads. • Latest Edition IEEE Std 1003.1,2004• Available for Linux and Unix OS family.• Available for Windows

• As Open Source http://sourceware.org/pthreads-win32/• Must be downloaded and installed in the windows development environment and

correctly bundled for release.

• C language interface• programming types and procedure calls• implemented as standalone library or as part of another library such as libc• Latest version compatible with C++.

Page 4: Multi-core Programming

Programming with POSIX* Threads 4

Pthreads threading model

• Threads exist within same process• All threads are peers

• No explicit parent-child model• Exception: “main thread” holds process information

• Pthreads API:– Thread management: creating, detaching, joining,

etc. – Mutexes: deal with synchronization– Condition variables: communications between

threads that share a mutex

Page 5: Multi-core Programming

Programming with POSIX* Threads 5

Compare with Win32 CreateThread

pthread_createint pthread_create(tid, attr, function, arg);

pthread_t *tid– handle of created threadconst pthread_attr_t *attr– attributes of thread to be createdvoid *(*function)(void *)– function to be mapped to threadvoid *arg– single argument to function

Page 6: Multi-core Programming

Programming with POSIX* Threads 6

pthread_create Explained

• Spawn a thread running the function• Thread handle returned via pthread_t

structure– Specify NULL to use default attributes

• Single argument sent to function– If no arguments to function, specify NULL

• Check error codes!EAGAIN - insufficient resources to create threadEINVAL - invalid attribute

Page 7: Multi-core Programming

Programming with POSIX* Threads 7

Example: Thread Creation#include <stdio.h>#include <pthread.h>

void *hello (void * arg) { printf(“Hello Thread\n”);

}

main() { pthread_t tid;

pthread_create(&tid, NULL, hello, NULL);

}

What Happens?

Page 8: Multi-core Programming

Programming with POSIX* Threads 8

Waiting for a Thread

int pthread_join(tid, val_ptr);

pthread_t tid– handle of joinable threadvoid **val_ptr– exit value returned by joined thread

Compare with Win32 WaitForSingleObject

Page 9: Multi-core Programming

Programming with POSIX* Threads 9

pthread_join Explained

• Calling thread waits for thread with handle tid to terminate– Only one thread can be joined– Thread must be joinable

• Exit value is returned from joined thread– Type returned is (void *)– Use NULL if no return value expected

ESRCH - thread (pthread_t) not foundEINVAL - thread (pthread_t) not joinable

Page 10: Multi-core Programming

Programming with POSIX* Threads 10

Thread States

• Pthreads threads have two states– joinable and detached

• Threads are joinable by default– Resources are kept until pthread_join– Can be reset with attributes or API call

• Detached threads cannot be joined– Resources can be reclaimed at termination– Cannot reset to be joinable

No equivalent for Win32 Threads

Page 11: Multi-core Programming

Programming with POSIX* Threads 11

Example: Multiple Threads#include <stdio.h>#include <pthread.h>#define NUM_THREADS 4

void *hello (void *arg) {

printf(“Hello Thread\n”); } main() { pthread_t tid[NUM_THREADS]; for (int i = 0; i < NUM_THREADS; i++) pthread_create(&tid[i], NULL, hello, NULL);

for (int i = 0; i < NUM_THREADS; i++) pthread_join(tid[i], NULL);}

Page 12: Multi-core Programming

Programming with POSIX* Threads 12

What’s Wrong?

• What is printed for myNum?void *threadFunc(void *pArg) { int* p = (int*)pArg; int myNum = *p; printf( “Thread number %d\n”, myNum);}. . .// from main():for (int i = 0; i < numThreads; i++) { pthread_create(&tid[i], NULL, threadFunc, &i);}

void *threadFunc(void *pArg) { int* p = (int*)pArg; int myNum = *p; printf( “Thread number %d\n”, myNum);}. . .// from main():for (int i = 0; i < numThreads; i++) { pthread_create(&tid[i], NULL, threadFunc, &i);}

Page 13: Multi-core Programming

Programming with POSIX* Threads 13

Solution – “Local” Storagevoid *threadFunc(void *pArg) { int myNum = *((int*)pArg); printf( “Thread number %d\n”, myNum);}. . .

// from main():for (int i = 0; i < numThreads; i++) { tNum[i] = i; pthread_create(&tid[i], NULL, threadFunc, &tNum[i]);}

Page 14: Multi-core Programming

Programming with POSIX* Threads 14

Pthreads Mutex Variables• Simple, flexible, and efficient• Enables correct programming structures for avoiding

race conditions • New types– pthread_mutex_t

• the mutex variable– pthread_mutexattr_t

• mutex attributes• Before use, mutex must be initialized

Compare with Win32 Mutex and Critical Section

Page 15: Multi-core Programming

Programming with POSIX* Threads 15

pthread_mutex_initint pthread_mutex_init( mutex, attr );

pthread_mutex_t *mutex– mutex to be initializedconst pthread_mutexattr_t *attr– attributes to be given to mutex

ENOMEM - insufficient memory for mutexEAGAIN - insufficient resources (other than memory)EPERM - no privilege to perform operation

Page 16: Multi-core Programming

Programming with POSIX* Threads 16

Alternate Initialization

• Can also use the static initializerPTHREAD_MUTEX_INITIALIZER

– Uses default attributes

• Programmer must always pay attention to mutex scope– Must be visible to threads

pthread_mutex_t mtx1 = PTHREAD_MUTEX_INITIALIZER;

Compare with Win32 InitializeCriticalSection

Page 17: Multi-core Programming

Programming with POSIX* Threads 17

pthread_mutex_lock

int pthread_mutex_lock( mutex );

pthread_mutex_t *mutex• mutex to attempt to lock

Page 18: Multi-core Programming

Programming with POSIX* Threads 18

pthread_mutex_lock Explained

• Attempts to lock mutex– If mutex is locked by another thread, calling thread is

blocked• Mutex is held by calling thread until unlocked– Mutex lock/unlock must be paired or deadlock occursEINVAL - mutex is invalidEDEADLK - calling thread already owns mutex

Compare with Win32 WaitForSingleObject or

EnterCriticalSection

Page 19: Multi-core Programming

Programming with POSIX* Threads 19

pthread_mutex_unlock

int pthread_mutex_unlock( mutex );

pthread_mutex_t *mutex– mutex to be unlockedEINVAL - mutex is invalidEPERM - calling thread does not own mutex

Compare with Win32 ReleaseMutex or

LeaveCriticalSection

Page 20: Multi-core Programming

Programming with POSIX* Threads 20

Example: Use of mutex#define NUMTHREADS 4pthread_mutex_t gMutex; // why does this have to be global?int g_sum = 0;

void *threadFunc(void *arg) { int mySum = bigComputation(); pthread_mutex_lock( &gMutex ); g_sum += mySum; // threads access one at a time pthread_mutex_unlock( &gMutex );}

main() { pthread_t hThread[NUMTHREADS];

pthread_mutex_init( &gMutex, NULL ); for (int i = 0; i < NUMTHREADS; i++) pthread_create(&hThread[i],NULL,threadFunc,NULL);

for (int i = 0; i < NUMTHREADS; i++) pthread_join(hThread[i]); printf (“Global sum = %f\n”, g_sum);}

Page 21: Multi-core Programming

Programming with POSIX* Threads 21

Condition Variables

• Mutexes implement synchronization by controlling thread access to data

• Condition variables allow threads to synchronize based upon the actual value of data

• Condition variable is associated with an arbitrary conditional – Operations: wait and signal

• Provides mutual exclusion Compare with Win32 Events

Page 22: Multi-core Programming

Programming with POSIX* Threads 22

Condition Variable and Mutex

• Mutex is associated with condition variable– Protects evaluation of the conditional expression– Prevents race condition between signaling thread

and threads waiting on condition variable

Page 23: Multi-core Programming

Programming with POSIX* Threads 23

Lost and Spurious Signals

• Signal to condition variable is not saved– If no thread waiting, signal is “lost”– Thread can be deadlocked waiting for signal that

will not be sent• Condition variable can (rarely) receive

spurious signals– Slowed execution from predictable signals– Need to retest conditional expression

Page 24: Multi-core Programming

Programming with POSIX* Threads 24

Condition Variable Algorithm

Main Thread• Declare and initialize global data/variables

which require synchronization (such as "count")

• Declare and initialize a condition variable object

• Declare and initialize an associated mutex • Create threads A and B to do work

Page 25: Multi-core Programming

Programming with POSIX* Threads 25

Condition Variable AlgorithmThread A• Do work up to the point where a certain condition must occur (such

as "count" must reach a specified value) • Lock associated mutex and check value of a global variable • Call pthread_cond_wait() to perform a blocking wait for signal from

Thread-B. Note that a call to pthread_cond_wait() automatically and atomically unlocks the associated mutex variable so that it can be used by Thread-B.

• When signalled, wake up. Mutex is automatically and atomically locked.

• Explicitly unlock mutex • Continue

Page 26: Multi-core Programming

Programming with POSIX* Threads 26

Condition Variable Algorithm

Thread B• Do work • Lock associated mutex • Change the value of the global variable that Thread-

A is waiting upon. • Check value of the global Thread-A wait variable. If

it fulfills the desired condition, signal Thread-A. • Unlock mutex. • Continue

Page 27: Multi-core Programming

Programming with POSIX* Threads 27

Condition Variables

• pthread_cond_init, pthread_cond_destroy– initialize/destroy condition variable

• pthread_cond_wait– thread goes to sleep until signal of condition variable

• pthread_cond_signal– signal release of condition variable

• pthread_cond_broadcast– broadcast release of condition variable

Page 28: Multi-core Programming

Programming with POSIX* Threads 28

Condition Variable Types

• Data types used– pthread_cond_t• the condition variable

– pthread_condattr_t• condition variable attributes

• Before use, condition variable (and mutex) must be initialized

Page 29: Multi-core Programming

Programming with POSIX* Threads 29

pthread_cond_init

int pthread_cond_init( cond, attr );

pthread_cond_t *cond– condition variable to be initializedconst pthread_condattr_t *attr– attributes to be given to condition variable

ENOMEM - insufficient memory for condition variableEAGAIN - insufficient resources (other than memory)EBUSY - condition variable already intializedEINVAL - attr is invalid

Page 30: Multi-core Programming

Programming with POSIX* Threads 30

Alternate Initialization• Can also use the static initializer– PTHREAD_COND_INITIALIZER

– Uses default attributes

• Programmer must always pay attention to condition (and mutex) scope– Must be visible to threads

pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;

Compare with Win32 CreateEvent

Page 31: Multi-core Programming

Programming with POSIX* Threads 31

pthread_cond_wait

int pthread_cond_wait( cond, mutex );

pthread_cond_t *cond• condition variable to wait on

pthread_mutex_t *mutex• mutex to be unlocked

Compare with Win32 WaitForSingleObject

Page 32: Multi-core Programming

Programming with POSIX* Threads 32

pthread_cond_wait Explained

• Thread put to “sleep” waiting for signal on cond

• Mutex is unlocked – Allows other threads to acquire lock– When signal arrives, mutex will be reacquired

before pthread_cond_wait returnsEINVAL - cond or mutex is invalidEINVAL - different mutex for concurrent waitsEINVAL - calling thread does not own mutex

Page 33: Multi-core Programming

Programming with POSIX* Threads 33

pthread_cond_signal

int pthread_cond_signal( cond );

pthread_cond_t *cond• condition variable to be signaled

Compare with Win32 Pulse Event

Page 34: Multi-core Programming

Programming with POSIX* Threads 34

pthread_cond_signal Explained

• Signal condition variable, wake one waiting thread

• If no threads waiting, no action taken– Signal is not saved for future threads

• Signaling thread need not have mutex– May be more efficient– Problem may occur if thread priorities usedEINVAL - cond is invalid

Page 35: Multi-core Programming

Programming with POSIX* Threads 35

pthread_cond_broadcast

int pthread_cond_broadcast( cond );

pthread_cond_t *cond• condition variable to signal

Page 36: Multi-core Programming

Programming with POSIX* Threads 36

pthread_cond_broadcast Explained

• Wake all threads waiting on condition variable• If no threads waiting, no action taken– Broadcast is not saved for future threads

• Signaling thread need not have mutexEINVAL - cond is invalid

Compare with Win32 Auto & Manual Reset Events

Page 37: Multi-core Programming

Programming with POSIX* Threads 37

Programming with POSIX* ThreadsWhat’s Been Covered

• How to create threads to execute work encapsulated within functions

• Coordinate shared access between threads to avoid race conditions