CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a...

29
CS11 C++ DGC Lecture 3 Spring 2006-2007

Transcript of CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a...

Page 1: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

CS11 C++ DGC

Lecture 3Spring 2006-2007

Page 2: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Today’s Topics

POSIX condition variablesfriend access modifierStatic functionsThe Standard Template Library

Page 3: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

This Week’s Lab

Implement a thread poolVery common threading component

Pool of N threadsThreads are expensive to create and destroyToo many threads can overwhelm the system

Context-switches, or simple resource usageJobs are added to a work queueAs threads become idle, they take jobs off the work queue and execute them

Many variations on this theme!

Page 4: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Checking for Work

How can a thread wait for jobs to show up?Could sit in a loop, polling the work queue

// Get a job.Job *pJob = 0;do {mutex.lock();if (workQueue.size() > 0)pJob = workQueue.pop_front();

mutex.unlock();} while (pJob == 0);

Very inefficient approach!Will consume way too many CPU resourcesWill actually hinder progress of other threads!

Page 5: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Passive Waiting

Would like to put a waiting thread to sleepIt stops running, or consuming any CPU resourcesThread is suspended

Later, wake the thread upWhen some condition becomes true, the thread can resume its computatione.g. when work queue receives another job, wake up a worker thread

Page 6: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

POSIX Condition Variables

Condition variables provide this kind of interaction

A thread can wait for a condition to become trueAnother thread can signal when the condition becomes true

Also supports multiple-thread communicationSeveral threads can wait for a condition to become trueA thread can broadcast when the condition becomes true

Page 7: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Condition Variables and Mutexes

Condition variables have an associated mutexThe condition applies to shared state…The mutex is used for guarding that shared state

Waiting thread procedure:Lock the mutexCheck for desired conditionIf condition isn’t true, wait on the condition variable

Mutex is automatically unlocked when thread waits on condition variable

…so some other thread can acquire the mutex and act on the shared state

When waiting thread is waken up:Automatically reacquires the mutex before proceeding

Page 8: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Signaling on a Condition Variable

Signaling thread procedure:Lock the mutexModify the shared state

Now the condition should be trueSignal on the condition variableUnlock the mutex

When thread signals on condition variable, one waiting thread wakes up

That thread can’t progress until signaling thread actually unlocks the mutexRemember: waiting thread must reacquire the mutex lock before continuing on.

Page 9: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Wakeups

For waiting threads, important to check condition in a loop

Waiting on a condition variable can generate spurious wakeups!Also, if multiple threads are signaled, condition may be false again by the time a particular thread gets to the mutex

Follow this pattern:Lock mutexWhile condition isn’t true:

Wait on condition variableUnlock mutex

Page 10: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Condition Variable API

Type: pthread_cond_tTo initialize:int pthread_cond_init(pthread_cond_t *,

pthread_condattr_t *)To clean up:int pthread_cond_destroy(pthread_cond_t *)To wait:int pthread_cond_wait(pthread_cond_t *,

pthread_mutex_t *)Also pthread_cond_timedwait(...) too

To signal:int pthread_cond_signal(pthread_cond_t *)To broadcast:int pthread_cond_broadcast(pthread_cond_t *)

Page 11: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Condition Variable Wrapper

Would like to create a C++ wrapper class for condition variables too

Resource Allocation Is Initialization patternSimplifying constraint:

Associate a condition variable with one mutexTechnically, can use a condition variable with multiple mutexes, but is tricky and bug-prone!

Pass a Mutex-reference to ConditionVariableconstructor

When someone calls wait(), use specified Mutex

Page 12: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Accessing the Mutex

Problem:Condition variable needs a pthread_mutex_t pointer in order to waitMutex class declares its pthread_mutex_t variable as privateShouldn’t expose this state, if at all possible!

Solution: use the friend access modifierMutex declares ConditionVariable to be a friend classConditionVariable can access private members of Mutex

Page 13: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

friend and Encapsulation

friend modifier should be used very rarely!Allows encapsulation to be violated!Other classes and functions can access or mutate private state values

In this case:Mutex and ConditionVariable violate encapsulation with respect to each other……but doing so allows Mutex to preserve encapsulation towards other classes

Page 14: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

friend Syntax

Declare friend classes and functions in class declaration

class Mutex {// Condition variable accesses POSIX// mutex variable directly.friend class ConditionVariable;

pthread_mutex_t m;public:

...};

Friend class can access private stateAlways document reasons for this!!!

Page 15: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

friend Syntax (2)

Can also declare friend functions:class Foo {

friend int bar(const Foo &f);

int secret;public:

...};

int bar(const Foo &f) {cout << f.secret << endl;

}

Again, only use when absolutely necessary

Page 16: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Pool Threads

Thread-pool threads have a simple existence:Wait for a job to show up.When a job arrives, do it.Wait for more jobs to show up.

ThreadPool will be a classInstantiate the class to make a thread pool to use

Problem: How to specify the thread function?Need a pointer to some thread functionCan’t use a member function, since that would also require an object

Page 17: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Static Functions

All pool threads will have same behaviorRegardless of what thread-pool they are a part of!

ThreadPool class can declare a function to use for pool threadsDeclare the function static, to indicate that it’s not part of an object

Static function is still part of the class it’s inIt can access private members, etc.Don’t call static function on an objectthis is not defined in static function’s body

Page 18: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Static Function Syntax

Declare static function in ThreadPool declarationclass ThreadPool {

private deque<Job *> workQueue;...static void *threadFunc(void *);

public:...

};

Thread function is private: it is encapsulated within the ThreadPool classCan pass thread function to threads created in the poolCan pass a pointer to the ThreadPool object as the thread function’s argument

Page 19: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Static Function Implementation

Inside static function, can use ThreadPool statevoid * ThreadPool::threadFunc(void *arg) {

assert(arg != 0);ThreadPool *pool = (ThreadPool *) arg;

while (true) {pool->mutex.lock();while (pool->workQueue.size() == 0) {

...}pool->mutex.unlock();

}}Don’t need to say “static” in function definition

Page 20: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Pool Queues

Need a queue for incomplete jobsJobs are represented as an abstract class

Provide implementation of abstract functions, to implement specific kinds of jobsThread pool can be coded against generic Job base-class

Can also use a queue for completed jobsIf a job involves computations, might need to retrieve computed results when job is completed

Page 21: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

The Standard Template Library

Use Standard Template Library collections in thread pool

Generic, customizable template classesManage collections of objects

Different STL collections have different characteristics

Functional differencesDifferent performance characteristics

Page 22: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

STL Containers

Sequences store their elements in linear sequential order

Variable size; can grow or shrinkvector – random access, constant append time, linear insert time, linear prepend timedeque – like vector, but constant prepend time toolist – doubly linked list, constant insert anywhere, only sequential accessslist – singly linked list, only forward traversalbit_vector – vector of bools, optimized for space!

Page 23: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Associative Containers

Support efficient retrieval based on keysNo support for inserting at a specific position

set – stores keys; each appears only oncemap – stores (key,value) pairs; each key appears only oncemultiset, multimap – like the above, but keys can appear multiple timesThese are Sorted Associative Containers

They don’t hash the keys! Most operations are O(log(N))But, they do keep their entries sorted by key.

Page 24: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Job Queues

Thread-pool users will append jobs on end of the queuePool threads will pull jobs from front of queueGood candidates for work queue would be deque or listdeque is probably fastest and easiest to use

Pool threads also need stored and managedCan use vector for this since count doesn’t need to change

Page 25: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Element-Access Operations

Sequences provide many kinds of element-access operationsCan use [] operator to retrieve individual elements

vector<int> v(3); // Vector of 3 elementsv[0] = 7;v[1] = v[0] + 3;v[2] = v[0] + v[1];

Can use push_back() and push_front() to add new elements

vector<Thread*> threads;for (int i = 0; i < numThreads; i++)

threads.push_back(new Thread(...));pop_back() and pop_front() to remove elements, etc.

Page 26: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Iterating Over Collections

All collections provide iterators for traversing their contentsAn iterator is a generalization of a pointer

Iterators provide the same operations as pointers(Pointers and iterators can be used in many similar ways)

An iterator points to a specific element of a collectionDereferencing the iterator returns the element it points toIncrementing an iterator moves it to the next element

Example:vector<Thread*>::iterator it;for (it = threads.begin(); it != threads.end(); it++){(*it)->join(); // Type of *it is Thread*delete *it;

}

Page 27: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Iterating over Collections (2)

Our example code:vector<Thread*>::iterator it;for (it = threads.begin(); it != threads.end(); it++){(*it)->join(); // Type of *it is Thread*delete *it;

}All collections provide nested typedefs for iterators

vector<Thread*>::iterator is an iterator for a vector of Thread* elementsvector<Thread*>::const_iterator is a read-only iterator, if the vector itself is const

All collections provide begin() and end() accessorsbegin() returns an iterator pointing to first elementend() returns an iterator pointing just past the last element

Page 28: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

STL Resources

Complete STL reference documentation available onlineThe SGI STL Documentation

http://www.sgi.com/tech/stl/index.html

Feel free to experiment with the STL in your assignment

Very feature-rich set of templates and operations

Page 29: CS11 C++ DGCcourses.cms.caltech.edu/cs11/material/dgc/lectures/... · This Week’s Lab Implement a thread pool Very common threading component Pool of N threads Threads are expensive

Using the Thread Pool

This week you will just test the thread poolCreate a simple “test job” class, similar to POSIX “Hello world” functionalityMake the test job pause for some amount of timeMake sure the pool actually runs jobs in parallelMake sure the thread pool shuts down correctly

Next week:Plug your thread pool into a Mandelbrot fractal drawing programParallelize the generator to take advantage of multiple CPUs