threads

59
Threads Threads

Upload: kelsey-woodward

Post on 30-Dec-2015

19 views

Category:

Documents


0 download

DESCRIPTION

Threads. Progressing With Parallel Processing(PWPP?) eWeek (09/18/06) Vol. 23, No. 37, P. D5 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Threads

ThreadsThreads

Page 2: Threads

Progressing With Parallel Processing (PWPP?)

eWeek (09/18/06) Vol. 23, No. 37, P. D5

Multithreading skills are becoming essential as parallel processing hardware proliferates, and developers ignore at their own peril indications of this trend such as Intel's investments in college curriculum and resources for multithread development training. The Java programming language supports the expression of concurrency in the same language developers are already employing for application logic, while powerful abstractions for C++ are also offered by concurrency toolkits and frameworks. Being able to count the threads developers are using on the fingers of one hand is folly, according to principal author of "Java Concurrency in Practice" Brian Goetz. He and his five co-authors note that "The need for thread safety is contagious," because "frameworks may create threads on your behalf, and code called from these threads must be thread-safe.“ It is the authors' contention that developers should never lose sight of the application state and avoid becoming overwhelmed by threading mechanisms. Developers must also keep in mind that careless habits that are acceptable in single-thread environments may be exposed in multithread environments.

Page 3: Threads

2.2 Threads2.2 Threads

Process: address space + code executionProcess: address space + code execution

There is no There is no lawlaw that states that a process that states that a process cannot have more than one “line” of execution.cannot have more than one “line” of execution.

Threads: Threads: singlesingle address space + address space + manymany threads of executionthreads of execution

Page 4: Threads

2.2 Threads2.2 Threads

Process: address space + code executionProcess: address space + code execution separate global variablesseparate global variables separate stack (and stack address space)separate stack (and stack address space) separate open filesseparate open files separate signalsseparate signals separate child processes, …separate child processes, …

Page 5: Threads

2.2 Threads2.2 Threads

Process: address space + code executionProcess: address space + code execution separate global variablesseparate global variables separate stack (and stack address space)separate stack (and stack address space) separate open filesseparate open files separate signalsseparate signals separate child processes, …separate child processes, …

Threads: Threads: singlesingle address space + address space + manymany threads of threads of executionexecution

shared global variablesshared global variables shared stack address space (but separate stacks)shared stack address space (but separate stacks) shared open filesshared open files shared signalsshared signals shared child processes, ,,,shared child processes, ,,,

Page 6: Threads

ThreadsThreads

Process – used to group resources together; has at Process – used to group resources together; has at least one threadleast one thread

Thread – actual entity scheduled for execution on Thread – actual entity scheduled for execution on CPUCPU Threads are sometimes called lightweight processes Threads are sometimes called lightweight processes

(LWPs)(LWPs)

Multithreading – multiple threads in the same Multithreading – multiple threads in the same processprocess

Page 7: Threads

32

Page 8: Threads
Page 9: Threads
Page 10: Threads

Thread functionsThread functions

Create threads:Create threads:

#include <pthread.h>#include <pthread.h>

int pthread_create (int pthread_create (

pthread_t* thread,pthread_t* thread,

pthread_attr_t* attr,pthread_attr_t* attr,

void* (*start_routine)(void*),void* (*start_routine)(void*),

void* arg );void* arg );

Page 11: Threads

Thread functionsThread functions

Create threads:Create threads:

#include <pthread.h>#include <pthread.h>

int pthread_create (int pthread_create (

pthread_t* thread,pthread_t* thread,

pthread_attr_t* attr,pthread_attr_t* attr,

void* (*start_routine)(void*)void* (*start_routine)(void*),,

void* arg );void* arg );

This parameter, start_routine, is the address of a function (*start_routine).

This function has one argument, a “generic” pointer (void*).

This function returns a “generic” pointer (void*).(We will see an example shortly.)

Page 12: Threads

Thread terminationThread termination

void pthread_exit ( void* retval );void pthread_exit ( void* retval );

int pthread_cancel ( pthread_t thread );int pthread_cancel ( pthread_t thread );

Page 13: Threads

Types of processes (or threads)Types of processes (or threads)

1.1. compute boundcompute bound

2.2. I/O boundsI/O bounds

3.3. mixedmixed

Page 14: Threads

Why threads?Why threads?

easier to create a thread than a processeasier to create a thread than a process share resourcesshare resources computation and I/O within a single computation and I/O within a single

process on a single processor can be process on a single processor can be overlappedoverlapped

computation (and computation in other computation (and computation in other threads) within a single process on a threads) within a single process on a multiprocessor can be overlappedmultiprocessor can be overlapped

Page 15: Threads

Example: word processorExample: word processor

Multiple threads:Multiple threads:1.1. User interactionUser interaction

2.2. Document reformattingDocument reformatting

3.3. Automatic saving/backupsAutomatic saving/backups

Alternative is everything else stops when Alternative is everything else stops when (2) or (3) occurs.(2) or (3) occurs.

Page 16: Threads

Example: web serverExample: web server

dispatcher thread – handles incoming requestsdispatcher thread – handles incoming requests worker threads – performs requestworker threads – performs request

1.1. Checks cacheChecks cache

2.2. Reads from disk if necessaryReads from disk if necessary

3.3. Adds to cacheAdds to cache

Page 17: Threads

Threads and alternativesThreads and alternatives

1.1. ThreadsThreads retain the simple sequential, blocking model retain the simple sequential, blocking model while allowing for parallelism.while allowing for parallelism. May be in user space or kernel.May be in user space or kernel.

2.2. (alternative) The single threaded server retains the (alternative) The single threaded server retains the simple sequential, block model but performance simple sequential, block model but performance suffers (no parallelism).suffers (no parallelism).

3.3. (alternative) Finite state machine = each (alternative) Finite state machine = each computation has a saved state and there exists some computation has a saved state and there exists some set of events that can occur to change the state.set of events that can occur to change the state. high performance through parallelismhigh performance through parallelism uses nonblocking calls and interrupts (not simple)uses nonblocking calls and interrupts (not simple)

Page 18: Threads

ThreadsThreads

Thread types:Thread types:

1.1. detacheddetached relatively independentrelatively independent

2.2. joinablejoinable waiting for completionwaiting for completion

3.3. popup threadspopup threads like signal handlers that have their own threadslike signal handlers that have their own threads

Page 19: Threads

ThreadsThreads

Implementations:Implementations:1.1. user spaceuser space

scheduling is the responsibility of the userscheduling is the responsibility of the user

2.2. kernelkernel threads are scheduled by the OS (like threads are scheduled by the OS (like

processes)processes)

3.3. hybridhybrid win32 supports both threads (kernel), and fibers win32 supports both threads (kernel), and fibers

(user space)(user space)

Page 20: Threads

Pitfall: global variablesPitfall: global variables#include <stdio.h>#include <stdio.h>bool err = false;bool err = false;

void* t1 ( void* p ) {void* t1 ( void* p ) {……err = true;err = true;if (err) puts( "hello" ); //may never get here!if (err) puts( "hello" ); //may never get here!……

}}

void* t2 ( void* p ) {void* t2 ( void* p ) {……err = false;err = false;……

}}

int main ( int argc, char* argv[] ) {int main ( int argc, char* argv[] ) {……if (err) puts( "something bad happened." );if (err) puts( "something bad happened." );……

}}

global variable (shared by all threads)

Page 21: Threads

Pitfall: global variablesPitfall: global variables#include <stdio.h>#include <stdio.h>bool err = false;bool err = false;

void* t1 ( void* p ) {void* t1 ( void* p ) {……::err = true;::err = true;if (::err) puts( "hello" ); //may never get here!if (::err) puts( "hello" ); //may never get here!……

}}

void* t2 ( void* p ) {void* t2 ( void* p ) {……::err = false;::err = false;……

}}

int main ( int argc, char* argv[] ) {int main ( int argc, char* argv[] ) {……if (::err) puts( "something bad happened." );if (::err) puts( "something bad happened." );……

}}

Interesting note:

C++ scope resolution operator may be used to indicate global variable.

Page 22: Threads

Pitfall: global variablesPitfall: global variables#include <stdio.h>#include <stdio.h>bool err = false;bool err = false;

void* t1 ( void* p ) {void* t1 ( void* p ) {……err = true;err = true;if (err) puts( "hello" ); //may never get here!if (err) puts( "hello" ); //may never get here!……

}}

void* t2 ( void* p ) {void* t2 ( void* p ) {……err = false;err = false;……

}}

int main ( int argc, char* argv[] ) {int main ( int argc, char* argv[] ) {……if (err) puts( "something bad happened." );if (err) puts( "something bad happened." );……

}}

The main thread creates two additional threads, t1 and t2.

Pointers indicate next line to be executed by thread.

Page 23: Threads

Pitfall: global variablesPitfall: global variables#include <stdio.h>#include <stdio.h>bool err = false;bool err = false;

void* t1 ( void* p ) {void* t1 ( void* p ) {……err = true;err = true;if (err) puts( "hello" ); //may never get here!if (err) puts( "hello" ); //may never get here!……

}}

void* t2 ( void* p ) {void* t2 ( void* p ) {……err = false;err = false;……

}}

int main ( int argc, char* argv[] ) {int main ( int argc, char* argv[] ) {……if (err) puts( "something bad happened." );if (err) puts( "something bad happened." );……

}}

Say t1 executes this line.

Page 24: Threads

Pitfall: global variablesPitfall: global variables#include <stdio.h>#include <stdio.h>bool err = false;bool err = false;

void* t1 ( void* p ) {void* t1 ( void* p ) {……err = true;err = true;if (err) puts( "hello" ); //may never get here!if (err) puts( "hello" ); //may never get here!……

}}

void* t2 ( void* p ) {void* t2 ( void* p ) {……err = false;err = false;……

}}

int main ( int argc, char* argv[] ) {int main ( int argc, char* argv[] ) {……if (err) puts( "something bad happened." );if (err) puts( "something bad happened." );……

}}

But it gets interrupted.Now it’s t2’s turn.

Page 25: Threads

Pitfall: global variablesPitfall: global variables#include <stdio.h>#include <stdio.h>bool err = false;bool err = false;

void* t1 ( void* p ) {void* t1 ( void* p ) {……err = true;err = true;if (err) puts( "hello" ); //may never get here!if (err) puts( "hello" ); //may never get here!……

}}

void* t2 ( void* p ) {void* t2 ( void* p ) {……err = false;err = false;……

}}

int main ( int argc, char* argv[] ) {int main ( int argc, char* argv[] ) {……if (err) puts( "something bad happened." );if (err) puts( "something bad happened." );……

}}

So t2 executes.Now it’s t1’s turn.

Page 26: Threads

Pitfall: global variablesPitfall: global variables#include <stdio.h>#include <stdio.h>bool err = false;bool err = false;

void* t1 ( void* p ) {void* t1 ( void* p ) {……err = true;err = true;if (err) puts( "hello" ); //may never get here!if (err) puts( "hello" ); //may never get here!……

}}

void* t2 ( void* p ) {void* t2 ( void* p ) {……err = false;err = false;……

}}

int main ( int argc, char* argv[] ) {int main ( int argc, char* argv[] ) {……if (err) puts( "something bad happened." );if (err) puts( "something bad happened." );……

}}

t1 doesn’t print “hello.”Why not?It set err to true on the previous line!

Note: We get a different result if t2 went first!

Page 27: Threads

Pitfalls: global variablesPitfalls: global variables

Page 28: Threads

Pitfall: global variablesPitfall: global variables

Possible solutions:Possible solutions:

1.1. Don’t use ‘em.Don’t use ‘em.

2.2. Create thread-wide globals (using your own Create thread-wide globals (using your own libraries).libraries).

3.3. Other mechanisms (that we will explore in Other mechanisms (that we will explore in the future).the future).

Page 29: Threads

Other pitfallsOther pitfalls

Libraries may not be Libraries may not be reentrantreentrant Solution: rewrite the librarySolution: rewrite the library Solution: wrap each library call with a wrapperSolution: wrap each library call with a wrapper

Signals, alarms, and I/O may not be Signals, alarms, and I/O may not be thread specific.thread specific.

Page 30: Threads

Other pthread functionsOther pthread functions

int thread_yield ( );int thread_yield ( );

int pthread_join (int pthread_join (pthread_t th,pthread_t th,void** thread_return );void** thread_return );

Many, many othersMany, many others

Page 31: Threads

Multithreaded exampleMultithreaded example

Page 32: Threads

/*/* file:file: pt1.cpppt1.cpp date:date: 23-sep-200523-sep-2005 author:author: george j. grevera, ph.d.george j. grevera, ph.d. compile:compile: g++ -o pt1.exe pt1.cpp -lpthread -lmg++ -o pt1.exe pt1.cpp -lpthread -lm desc.:desc.: shell of a multithreaded appshell of a multithreaded app*/*/#include <math.h>#include <math.h>#include <pthread.h>#include <pthread.h>#include <stdio.h>#include <stdio.h>

//global variables//global variablesconst intconst int N = 10;N = 10; //max number of threads//max number of threadspthread_tpthread_t thread[ N ];thread[ N ]; //for thread id storage//for thread id storage//----------------------------------------------------------------------//----------------------------------------------------------------------

Additional system libraries that are needed.

Page 33: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------//program execution begins here.//program execution begins here.int main ( int argc, char* argv[] ) {int main ( int argc, char* argv[] ) {

//create N threads//create N threads for (int i=0; i<N; i++) {for (int i=0; i<N; i++) { pthread_create( &thread[i], 0, start_routine, (void*)i );pthread_create( &thread[i], 0, start_routine, (void*)i ); printf( "main: thread %d created. \n", thread[i] );printf( "main: thread %d created. \n", thread[i] ); }}

//wait for the N threads to finish//wait for the N threads to finish for (int i=0; i<N; i++) {for (int i=0; i<N; i++) { void* v;void* v; printf( "main: waiting \n" );printf( "main: waiting \n" ); pthread_join( thread[i], &v );pthread_join( thread[i], &v ); }}

printf( "main: returning \n" );printf( "main: returning \n" ); return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

Page 34: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------//example worker thread function.//example worker thread function.//this function does a lot of “work” (i.e., computation).//this function does a lot of “work” (i.e., computation).double doWork ( const int whoAmI ) {double doWork ( const int whoAmI ) { double sum = 0.0;double sum = 0.0; for (int i=0; i<10000000; i++) {for (int i=0; i<10000000; i++) { sum += sin( i ) * cos( i );sum += sin( i ) * cos( i ); }} return sum;return sum;}}//----------------------------------------------------------------------//----------------------------------------------------------------------//main thread function//main thread functionvoid* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; printf( "%d processing \n", whoAmI );printf( "%d processing \n", whoAmI );

doWork( whoAmI );doWork( whoAmI );

printf( "%d exit \n", whoAmI );printf( "%d exit \n", whoAmI ); return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

Page 35: Threads

/*/*file: pt1.cppfile: pt1.cppdate: 23-sep-2005date: 23-sep-2005author: george j. grevera, ph.d.author: george j. grevera, ph.d.compile: g++ -o pt1.exe pt1.cpp -lpthread -lmcompile: g++ -o pt1.exe pt1.cpp -lpthread -lmdesc.: shell of a multithreaded appdesc.: shell of a multithreaded app*/*/#include <math.h>#include <math.h>#include <pthread.h>#include <pthread.h>#include <stdio.h>#include <stdio.h>

//global variables//global variablesconst int N = 10; //max number of threadsconst int N = 10; //max number of threadspthread_t thread[N]; //for thread id storagepthread_t thread[N]; //for thread id storage//----------------------------------------------------------------------//----------------------------------------------------------------------//example worker thread function. this function does a lot of "work"//example worker thread function. this function does a lot of "work"// (i.e., computation).// (i.e., computation).double doWork ( const int whoAmI ) {double doWork ( const int whoAmI ) { double sum = 0.0;double sum = 0.0; for (int i=0; i<10000000; i++) {for (int i=0; i<10000000; i++) { sum += sin( i ) * cos( i );sum += sin( i ) * cos( i ); }} return sum;return sum;}}//----------------------------------------------------------------------//----------------------------------------------------------------------//main thread function//main thread functionvoid* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; printf( "%d processing \n", whoAmI );printf( "%d processing \n", whoAmI );

doWork( whoAmI );doWork( whoAmI );

printf( "%d exit \n", whoAmI );printf( "%d exit \n", whoAmI ); return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------//program execution begins here.//program execution begins here.int main ( const int argc, const char* const argv[] ) {int main ( const int argc, const char* const argv[] ) {

//create N threads//create N threads for (int i=0; i<N; i++) {for (int i=0; i<N; i++) { pthread_create( &thread[i], 0, start_routine, (void*)i );pthread_create( &thread[i], 0, start_routine, (void*)i ); printf( "main: thread %d created. \n", thread[i] );printf( "main: thread %d created. \n", thread[i] ); }}

//wait for the N threads to finish//wait for the N threads to finish for (int i=0; i<N; i++) {for (int i=0; i<N; i++) { void* v;void* v; printf( "main: waiting \n" );printf( "main: waiting \n" ); pthread_join( thread[i], &v );pthread_join( thread[i], &v ); }}

printf( "main: returning \n" );printf( "main: returning \n" ); return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

complete example

Page 36: Threads

Multithreading discussionMultithreading discussion

pthread_create only allows a single pthread_create only allows a single parameter to be passed to the threadparameter to be passed to the thread

pthread_join only allows a single pthread_join only allows a single parameter to be returned from a threadparameter to be returned from a thread

How can we pass and return many How can we pass and return many parameters?parameters?

Page 37: Threads

MULTITHREADING: MULTITHREADING: ADVANCED TOPICADVANCED TOPIC

Page 38: Threads

Multithreading: advanced topicMultithreading: advanced topic

We know that process memory is shared We know that process memory is shared among all threads.among all threads.

We know that the stack is part of the We know that the stack is part of the process memory.process memory.

Therefore the stack is part of the memory Therefore the stack is part of the memory that is shared among the threads.that is shared among the threads.

How can we demonstrate that the stack is How can we demonstrate that the stack is shared among threads?shared among threads?

Page 39: Threads

/*/*This program demonstrates that, although stack variables are notThis program demonstrates that, although stack variables are notshared among threads, stack memory (_all_ process memory) is indeed shared among threads, stack memory (_all_ process memory) is indeed shared by threads.shared by threads.

g++ -o sharedStack.exe sharedStack.cpp -lpthread -lm -lrtg++ -o sharedStack.exe sharedStack.cpp -lpthread -lm -lrt*/*/#include <iostream>#include <iostream>#include <math.h>#include <math.h>#include <pthread.h>#include <pthread.h>#include <sched.h>#include <sched.h>#include <unistd.h>#include <unistd.h>

using namespace std;using namespace std;

const int N = 2; //max number of threadsconst int N = 2; //max number of threads

//this will be a pointer to a local variable in thread 0.//this will be a pointer to a local variable in thread 0.static int* whoAmIPointer = NULL;static int* whoAmIPointer = NULL;//----------------------------------------------------------------------//----------------------------------------------------------------------

From where are local variables allocated?

Page 40: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------int main ( const int argc, const char* const argv[] ) {int main ( const int argc, const char* const argv[] ) { pthread_t thread[::N]; //for thread id storagepthread_t thread[::N]; //for thread id storage //create N threads//create N threads for (int i=0; i< ::N; i++) {for (int i=0; i< ::N; i++) { pthread_create( &thread[i], 0, start_routine, (void*)i );pthread_create( &thread[i], 0, start_routine, (void*)i ); cout << "main: thread " << i << " created with id=" << thread[i]cout << "main: thread " << i << " created with id=" << thread[i] << endl;<< endl; }} //wait for the N threads to finish//wait for the N threads to finish for (int i=0; i< ::N; i++) {for (int i=0; i< ::N; i++) { void* v;void* v; cout << "main: wait" << endl;cout << "main: wait" << endl; pthread_join( thread[i], &v );pthread_join( thread[i], &v ); }}

cout << "main: returning" << endl;cout << "main: returning" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

Nothing new here.

Page 41: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------void* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; int whoAmICopy = whoAmI;int whoAmICopy = whoAmI; cout << whoAmI << " processing" << endl;cout << whoAmI << " processing" << endl;

if (whoAmI==0) { //is this thread 0?if (whoAmI==0) { //is this thread 0? //make the global var point to my local var//make the global var point to my local var ::whoAmIPointer = &whoAmI;::whoAmIPointer = &whoAmI; sched_yield();sched_yield(); sleep( 5 );sleep( 5 ); } else {} else { //this is not thread 0 so wait until thread 0 sets the global var//this is not thread 0 so wait until thread 0 sets the global var // that points to thread 0's local var.// that points to thread 0's local var. while (::whoAmIPointer==NULL) {while (::whoAmIPointer==NULL) { sched_yield();sched_yield(); }} //change thread 0's local var//change thread 0's local var *::whoAmIPointer = 92;*::whoAmIPointer = 92; }}

if (whoAmI!=whoAmICopy) {if (whoAmI!=whoAmICopy) { cout << "Hey! Wait a minute! Somebody changed who I am from "cout << "Hey! Wait a minute! Somebody changed who I am from " << whoAmICopy << " to " << whoAmI << "!" << endl;<< whoAmICopy << " to " << whoAmI << "!" << endl; }}

cout << whoAmI << " done" << endlcout << whoAmI << " done" << endl << whoAmI << " exit" << endl;<< whoAmI << " exit" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

What does :: mean in C++?

Page 42: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------void* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; int whoAmICopy = whoAmI;int whoAmICopy = whoAmI; cout << whoAmI << " processing" << endl;cout << whoAmI << " processing" << endl;

if (whoAmI==0) { //is this thread 0?if (whoAmI==0) { //is this thread 0? //make the global var point to my local var//make the global var point to my local var ::whoAmIPointer = &whoAmI;::whoAmIPointer = &whoAmI; sched_yield();sched_yield(); sleep( 5 );sleep( 5 ); } else {} else { //this is not thread 0 so wait until thread 0 sets the global var//this is not thread 0 so wait until thread 0 sets the global var // that points to thread 0's local var.// that points to thread 0's local var. while (::whoAmIPointer==NULL) {while (::whoAmIPointer==NULL) { sched_yield();sched_yield(); }} //change thread 0's local var//change thread 0's local var *::whoAmIPointer = 92;*::whoAmIPointer = 92; }}

if (whoAmI!=whoAmICopy) {if (whoAmI!=whoAmICopy) { cout << "Hey! Wait a minute! Somebody changed who I am from "cout << "Hey! Wait a minute! Somebody changed who I am from " << whoAmICopy << " to " << whoAmI << "!" << endl;<< whoAmICopy << " to " << whoAmI << "!" << endl; }}

cout << whoAmI << " done" << endlcout << whoAmI << " done" << endl << whoAmI << " exit" << endl;<< whoAmI << " exit" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

What does :: mean in C++?

:: is the C++ scope resolution operator. In this case, it refers to a global variable.

Page 43: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------void* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; int whoAmICopy = whoAmI;int whoAmICopy = whoAmI; cout << whoAmI << " processing" << endl;cout << whoAmI << " processing" << endl;

if (whoAmI==0) { //is this thread 0?if (whoAmI==0) { //is this thread 0? //make the global var point to my local var//make the global var point to my local var ::whoAmIPointer = &whoAmI;::whoAmIPointer = &whoAmI; sched_yield();sched_yield(); sleep( 5 );sleep( 5 ); } else {} else { //this is not thread 0 so wait until thread 0 sets the global var//this is not thread 0 so wait until thread 0 sets the global var // that points to thread 0's local var.// that points to thread 0's local var. while (::whoAmIPointer==NULL) {while (::whoAmIPointer==NULL) { sched_yield();sched_yield(); }} //change thread 0's local var//change thread 0's local var *::whoAmIPointer = 92;*::whoAmIPointer = 92; }}

if (whoAmI!=whoAmICopy) {if (whoAmI!=whoAmICopy) { cout << "Hey! Wait a minute! Somebody changed who I am from "cout << "Hey! Wait a minute! Somebody changed who I am from " << whoAmICopy << " to " << whoAmI << "!" << endl;<< whoAmICopy << " to " << whoAmI << "!" << endl; }}

cout << whoAmI << " done" << endlcout << whoAmI << " done" << endl << whoAmI << " exit" << endl;<< whoAmI << " exit" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

Page 44: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------void* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; int whoAmICopy = whoAmI;int whoAmICopy = whoAmI; cout << whoAmI << " processing" << endl;cout << whoAmI << " processing" << endl;

if (whoAmI==0) { //is this thread 0?if (whoAmI==0) { //is this thread 0? //make the global var point to my local var//make the global var point to my local var ::whoAmIPointer = &whoAmI;::whoAmIPointer = &whoAmI; sched_yield();sched_yield(); sleep( 5 );sleep( 5 ); } else {} else { //this is not thread 0 so wait until thread 0 sets the global var//this is not thread 0 so wait until thread 0 sets the global var // that points to thread 0's local var.// that points to thread 0's local var. while (::whoAmIPointer==NULL) {while (::whoAmIPointer==NULL) { sched_yield();sched_yield(); }} //change thread 0's local var//change thread 0's local var *::whoAmIPointer = 92;*::whoAmIPointer = 92; }}

if (whoAmI!=whoAmICopy) {if (whoAmI!=whoAmICopy) { cout << "Hey! Wait a minute! Somebody changed who I am from "cout << "Hey! Wait a minute! Somebody changed who I am from " << whoAmICopy << " to " << whoAmI << "!" << endl;<< whoAmICopy << " to " << whoAmI << "!" << endl; }}

cout << whoAmI << " done" << endlcout << whoAmI << " done" << endl << whoAmI << " exit" << endl;<< whoAmI << " exit" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

Page 45: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------void* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; int whoAmICopy = whoAmI;int whoAmICopy = whoAmI; cout << whoAmI << " processing" << endl;cout << whoAmI << " processing" << endl;

if (whoAmI==0) { //is this thread 0?if (whoAmI==0) { //is this thread 0? //make the global var point to my local var//make the global var point to my local var ::whoAmIPointer = &whoAmI;::whoAmIPointer = &whoAmI; sched_yield();sched_yield(); sleep( 5 );sleep( 5 ); } else {} else { //this is not thread 0 so wait until thread 0 sets the global var//this is not thread 0 so wait until thread 0 sets the global var // that points to thread 0's local var.// that points to thread 0's local var. while (::whoAmIPointer==NULL) {while (::whoAmIPointer==NULL) { sched_yield();sched_yield(); }} //change thread 0's local var//change thread 0's local var *::whoAmIPointer = 92;*::whoAmIPointer = 92; }}

if (whoAmI!=whoAmICopy) {if (whoAmI!=whoAmICopy) { cout << "Hey! Wait a minute! Somebody changed who I am from "cout << "Hey! Wait a minute! Somebody changed who I am from " << whoAmICopy << " to " << whoAmI << "!" << endl;<< whoAmICopy << " to " << whoAmI << "!" << endl; }}

cout << whoAmI << " done" << endlcout << whoAmI << " done" << endl << whoAmI << " exit" << endl;<< whoAmI << " exit" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

Page 46: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------void* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; int whoAmICopy = whoAmI;int whoAmICopy = whoAmI; cout << whoAmI << " processing" << endl;cout << whoAmI << " processing" << endl;

if (whoAmI==0) { //is this thread 0?if (whoAmI==0) { //is this thread 0? //make the global var point to my local var//make the global var point to my local var ::whoAmIPointer = &whoAmI;::whoAmIPointer = &whoAmI; sched_yield();sched_yield(); sleep( 5 );sleep( 5 ); } else {} else { //this is not thread 0 so wait until thread 0 sets the global var//this is not thread 0 so wait until thread 0 sets the global var // that points to thread 0's local var.// that points to thread 0's local var. while (::whoAmIPointer==NULL) {while (::whoAmIPointer==NULL) { sched_yield();sched_yield(); }} //change thread 0's local var//change thread 0's local var *::whoAmIPointer = 92;*::whoAmIPointer = 92; }}

if (whoAmI!=whoAmICopy) {if (whoAmI!=whoAmICopy) { cout << "Hey! Wait a minute! Somebody changed who I am from "cout << "Hey! Wait a minute! Somebody changed who I am from " << whoAmICopy << " to " << whoAmI << "!" << endl;<< whoAmICopy << " to " << whoAmI << "!" << endl; }}

cout << whoAmI << " done" << endlcout << whoAmI << " done" << endl << whoAmI << " exit" << endl;<< whoAmI << " exit" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

Page 47: Threads

//----------------------------------------------------------------------//----------------------------------------------------------------------void* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; int whoAmICopy = whoAmI;int whoAmICopy = whoAmI; cout << whoAmI << " processing" << endl;cout << whoAmI << " processing" << endl;

if (whoAmI==0) { //is this thread 0?if (whoAmI==0) { //is this thread 0? //make the global var point to my local var//make the global var point to my local var ::whoAmIPointer = &whoAmI;::whoAmIPointer = &whoAmI; sched_yield();sched_yield(); sleep( 5 );sleep( 5 ); } else {} else { //this is not thread 0 so wait until thread 0 sets the global var//this is not thread 0 so wait until thread 0 sets the global var // that points to thread 0's local var.// that points to thread 0's local var. while (::whoAmIPointer==NULL) {while (::whoAmIPointer==NULL) { sched_yield();sched_yield(); }} //change thread 0's local var//change thread 0's local var *::whoAmIPointer = 92;*::whoAmIPointer = 92; }}

if (whoAmI!=whoAmICopy) {if (whoAmI!=whoAmICopy) { cout << "Hey! Wait a minute! Somebody changed who I am from "cout << "Hey! Wait a minute! Somebody changed who I am from " << whoAmICopy << " to " << whoAmI << "!" << endl;<< whoAmICopy << " to " << whoAmI << "!" << endl; }}

cout << whoAmI << " done" << endlcout << whoAmI << " done" << endl << whoAmI << " exit" << endl;<< whoAmI << " exit" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

How could this ever be true (if threads didn’t share stack memory)?

Page 48: Threads

/*/*This program demonstrates that, although stack variables are notThis program demonstrates that, although stack variables are notshared among threads, stack memory (_all_ process memory) is indeed shared among threads, stack memory (_all_ process memory) is indeed shared by threads.shared by threads.

g++ -o sharedStack.exe sharedStack.cpp -lpthread -lm -lrtg++ -o sharedStack.exe sharedStack.cpp -lpthread -lm -lrt*/*/#include <iostream>#include <iostream>#include <math.h>#include <math.h>#include <pthread.h>#include <pthread.h>#include <sched.h>#include <sched.h>#include <unistd.h>#include <unistd.h>

using namespace std;using namespace std;

const int N = 2; //max number of threadsconst int N = 2; //max number of threads

//this will be a pointer to a local variable in thread 0.//this will be a pointer to a local variable in thread 0.static int* whoAmIPointer = NULL;static int* whoAmIPointer = NULL;//----------------------------------------------------------------------//----------------------------------------------------------------------void* start_routine ( void* p ) {void* start_routine ( void* p ) { int whoAmI = (int)p;int whoAmI = (int)p; int whoAmICopy = whoAmI;int whoAmICopy = whoAmI; cout << whoAmI << " processing" << endl;cout << whoAmI << " processing" << endl;

if (whoAmI==0) { //is this thread 0?if (whoAmI==0) { //is this thread 0? //make the global var point to my local var//make the global var point to my local var ::whoAmIPointer = &whoAmI;::whoAmIPointer = &whoAmI; sched_yield();sched_yield(); sleep( 5 );sleep( 5 ); } else {} else { //this is not thread 0 so wait until thread 0 sets the global var//this is not thread 0 so wait until thread 0 sets the global var // that points to thread 0's local var.// that points to thread 0's local var. while (::whoAmIPointer==NULL) {while (::whoAmIPointer==NULL) { sched_yield();sched_yield(); }} //change thread 0's local var//change thread 0's local var *::whoAmIPointer = 92;*::whoAmIPointer = 92; }}

if (whoAmI!=whoAmICopy) {if (whoAmI!=whoAmICopy) { cout << "Hey! Wait a minute! Somebody changed who I am from "cout << "Hey! Wait a minute! Somebody changed who I am from " << whoAmICopy << " to " << whoAmI << "!" << endl;<< whoAmICopy << " to " << whoAmI << "!" << endl; }}

cout << whoAmI << " done" << endlcout << whoAmI << " done" << endl << whoAmI << " exit" << endl;<< whoAmI << " exit" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------int main ( const int argc, const char* const argv[] ) {int main ( const int argc, const char* const argv[] ) { pthread_t thread[::N]; //for thread id storagepthread_t thread[::N]; //for thread id storage //create N threads//create N threads for (int i=0; i< ::N; i++) {for (int i=0; i< ::N; i++) { pthread_create( &thread[i], 0, start_routine, (void*)i );pthread_create( &thread[i], 0, start_routine, (void*)i ); cout << "main: thread " << i << " created with id=" << thread[i]cout << "main: thread " << i << " created with id=" << thread[i] << endl;<< endl; }} //wait for the N threads to finish//wait for the N threads to finish for (int i=0; i< ::N; i++) {for (int i=0; i< ::N; i++) { void* v;void* v; cout << "main: wait" << endl;cout << "main: wait" << endl; pthread_join( thread[i], &v );pthread_join( thread[i], &v ); }}

cout << "main: returning" << endl;cout << "main: returning" << endl; return 0;return 0;}}//----------------------------------------------------------------------//----------------------------------------------------------------------

complete example

Page 49: Threads

WIN32, THREADS, & FIBERSWIN32, THREADS, & FIBERS

Page 50: Threads

Win32 thread functionsWin32 thread functions CreateThreadCreateThread

Creates a thread to execute within the virtual address space of the Creates a thread to execute within the virtual address space of the calling process.calling process.

ExitThreadExitThread Ends the calling thread.Ends the calling thread.

TerminateThreadTerminateThread Terminates a thread.Terminates a thread.

WaitForSingleObjectWaitForSingleObject Waits until the specified object is in the signaled state or the time-Waits until the specified object is in the signaled state or the time-

out interval elapses.out interval elapses.

GetExitCodeThreadGetExitCodeThread Retrieves the termination status of the specified thread.Retrieves the termination status of the specified thread.

Page 51: Threads

Win32 threads & fibersWin32 threads & fibers

Fibers (in win32 – not available in Linux)Fibers (in win32 – not available in Linux) a lightweight threada lightweight thread owned by threadowned by thread

Threads are preemptively scheduled.Threads are preemptively scheduled.

Fibers are not preemptively scheduled.Fibers are not preemptively scheduled. When thread is preempted, so is fiber.When thread is preempted, so is fiber. When thread is resumed, so is fiber.When thread is resumed, so is fiber.

may be scheduled by the owning threadmay be scheduled by the owning thread

Page 52: Threads

Win32 fibersWin32 fibers

““A fiber is a unit of execution that must be A fiber is a unit of execution that must be manually scheduled by the application. Fibers run manually scheduled by the application. Fibers run in the context of the threads that schedule them. in the context of the threads that schedule them. Each thread can schedule multiple fibers. Each thread can schedule multiple fibers. In In general, fibers do not provide advantages over a general, fibers do not provide advantages over a well-designed multithreaded application.well-designed multithreaded application. However, using fibers can make it easier to port However, using fibers can make it easier to port applications that were designed to schedule their applications that were designed to schedule their own threads.”own threads.” from from

http://msdn.microsoft.com/en-us/library/ms682661%28v=vs.85%29.aspx

Page 53: Threads

Win32 fibersWin32 fibers

““Fibers are not preemptively scheduled. You Fibers are not preemptively scheduled. You schedule a fiber by switching to it from another schedule a fiber by switching to it from another fiber. The system still schedules threads to run. fiber. The system still schedules threads to run. When a thread running fibers is preempted, its When a thread running fibers is preempted, its currently running fiber is preempted but remains currently running fiber is preempted but remains selected. The selected fiber runs when its selected. The selected fiber runs when its thread runs.”thread runs.” from from

http://msdn.microsoft.com/en-us/library/ms682661%28v=vs.85%29.aspx

Page 54: Threads

SOLARIS THREADS APISOLARIS THREADS API

Page 55: Threads

Table 7. Threads and pthreads functionsTable 7. Threads and pthreads functions(from http://www.ibm.com/developerworks/linux/library/l-portsolaris/index.html(from http://www.ibm.com/developerworks/linux/library/l-portsolaris/index.html

Solaris threads APISolaris threads API Linux POSIX threads APILinux POSIX threads API DescriptionDescription

thr_create()thr_create() pthread_create()pthread_create() Creates a new thread of control.Creates a new thread of control.

thr_exit()thr_exit() pthread_exit()pthread_exit() Terminates the execution of the calling thread.Terminates the execution of the calling thread.

thr_join()thr_join() pthread_join()pthread_join() Suspends the calling thread until the target threadSuspends the calling thread until the target thread

completes.completes.

thr_kill()thr_kill() pthread_kill()pthread_kill() Sends a signal to another thread.Sends a signal to another thread.

thr_self()thr_self() pthread_self()pthread_self() Returns the thread ID of the calling process.Returns the thread ID of the calling process.

thr_yield()thr_yield() sched_yield()sched_yield() Makes the current thread yield to another thread.Makes the current thread yield to another thread.

thr_getprio()thr_getprio() pthread_getschedparam()pthread_getschedparam() Retrieves a thread's priority parameters.Retrieves a thread's priority parameters.

thr_setprio()thr_setprio() pthread_setschedparam()pthread_setschedparam() Modifies a thread's priority parameters.Modifies a thread's priority parameters.

thr_getspecific()thr_getspecific() pthread_getspecific()pthread_getspecific() Binds a new thread-specific value to the key.Binds a new thread-specific value to the key.

thr_setspecific()thr_setspecific() pthread_setspecific()pthread_setspecific() Binds a new thread-specific value to the key.Binds a new thread-specific value to the key.

thr_getconcurrency()thr_getconcurrency() pthread_getconcurrency()pthread_getconcurrency() Gets thread concurrency level.Gets thread concurrency level.

thr_setconcurrency()thr_setconcurrency() pthread_setconcurrency()pthread_setconcurrency() Sets thread concurrency level.Sets thread concurrency level.

thr_sigsetmask()thr_sigsetmask() pthread_sigmask()pthread_sigmask() Changes or examines the calling thread's signal mask.Changes or examines the calling thread's signal mask.

thr_keycreate()thr_keycreate() pthread_key_create()pthread_key_create() Creates a key that locates data specific to a thread.Creates a key that locates data specific to a thread.

N/AN/A pthread_key_delete()pthread_key_delete() Deletes a key that locates data specific to a thread.Deletes a key that locates data specific to a thread.

thr_suspend()thr_suspend() N/AN/A Suspends the execution of the specified thread.Suspends the execution of the specified thread.

thr_continue()thr_continue() N/AN/A Resumes the execution of a suspended thread.Resumes the execution of a suspended thread.

fork1()fork1() fork()fork() Regular fork.Regular fork.

forkall()forkall() N/AN/A Replicate all forks.Replicate all forks.

Page 56: Threads

Threads and JavaThreads and Java

Two approaches:Two approaches:

1.1. subclass Threadsubclass Thread

2.2. implement Runnableimplement Runnable

Page 57: Threads

http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.htmlhttp://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html

class PrimeThread extends Thread {class PrimeThread extends Thread {

long minPrime;long minPrime;

PrimeThread ( long minPrime ) {PrimeThread ( long minPrime ) {

this.minPrime = minPrime;this.minPrime = minPrime;

}}

public void run ( ) {public void run ( ) {

// compute primes larger than minPrime// compute primes larger than minPrime

. . .. . .

}}

}}

PrimeThread p = new PrimeThread( 143 );p.start();

Page 58: Threads

http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.htmlhttp://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html

class PrimeRun implements Runnable {class PrimeRun implements Runnable {

long minPrime;long minPrime;

PrimeRun ( long minPrime ) {PrimeRun ( long minPrime ) {

this.minPrime = minPrime;this.minPrime = minPrime;

}}

public void run ( ) {public void run ( ) {

// compute primes larger than minPrime// compute primes larger than minPrime

. . .. . .

}}

}}

PrimeRun p = new PrimeRun( 143 );new Thread( p ).start();

Page 59: Threads

Java assignment:Java assignment:Find the min array value in parallel.Find the min array value in parallel. Write a Java program that:Write a Java program that:

1.1. Initializes an int array of N random values.Initializes an int array of N random values.

2.2. Write a function that finds the min value.Write a function that finds the min value.

3.3. Create two threads. One finds the min value Create two threads. One finds the min value in the first half; the other finds the min value in the first half; the other finds the min value in the second half.in the second half.