software architecture and larger system design issues lecture 3: synchronization

40
CSE 335: Software Design K. Stirewalt Software Architecture and Larger System Design Issues Lecture 3: Synchronization Topics: – Concurrent access to shared objects – Thread synchronization – Monitors

Upload: teal

Post on 08-Jan-2016

24 views

Category:

Documents


1 download

DESCRIPTION

Software Architecture and Larger System Design Issues Lecture 3: Synchronization. Topics: Concurrent access to shared objects Thread synchronization Monitors. Outline of course topics. Foundational OO concepts Synthetic concepts Software architecture and larger design issues - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Software Architecture and Larger System Design Issues

Lecture 3: Synchronization

Topics:– Concurrent access to shared objects– Thread synchronization– Monitors

Page 2: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Outline of course topics

Foundational OO concepts

Synthetic concepts

Software architecture and larger design issues– Example concern: Implementing systems with multiple loci of

control– Active objects– Techniques for implementing active objects:

• Have one actor (e.g., the GUIManager) periodically “cede” small quanta of control to other actors, which must be designed to perform their task in a series of small steps

• Allocate a system thread to “power” an actor

Software process issues

Page 3: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Concurrent access to shared data

Problem: Multiple active objects might access the same passive object “at the same time”– Generally OK if the active objects are only reading data

from the passive object(s)• but even this can be dangerous if the “reader” methods use

iterators or some other mutable operation– But if one or more active objects is modifying the data

members of the shared object, then we get anomalies

Example: Two active objects trying to pull elements from the same queue

To prevent these data-access anomalies requires synchronizing the active objects.

Page 4: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example

pull

pull

: Queueactor1 : … actor2 : …

Suppose Queue initially contains <“hello”, “world”, “foo”>.What are the possible outcomes?

Page 5: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Possible outcomes

Actor1 gets “hello”, actor2 gets “world”, queue contains <“foo”>

Actor1 gets “world”, actor2 gets “hello”, queue contains <“foo”>

Both actor1 and actor2 get “hello”, queue contains <“world”, “foo”>

Other possibilities, including corruption of internal state of queue...

Page 6: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Question: Is this interaction possible?

pull

pull

: Queueactor1 : … actor2 : …

Page 7: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

The sad news…

While the use of multiple threads is very powerful, to avoid errors requires:– Reasoning that “breaks” modularity, i.e., thinking

about how methods are implemented and how methods they invoke are implemented

– Reasoning about a large number of possible thread interleavings

Page 8: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example

class Queue { public:

… bool pull( string& s ) { bool retval = q.empty(); if (!retval) {

s = q.back();q.pop();

} return retval; }

… protected:

queue<string> q;};

Page 9: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example interleaving

:Queue actor2 : …actor1 : …

pull

empty

back

pop

pull

empty

back

pop

Question: What happens if queue contains A ?

Page 10: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example interleaving

:Queue actor2 : …actor1 : …

pull

empty

back

pop

pull

empty

back

pop

Question: What happens if queue contains A, B ?

Page 11: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

What can go wrong here?Queue contains: A,B,C

:Queue actor2 : …actor1 : …

pull

empty

back

pop

pull

empty

back

pop

Page 12: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

To prevent unsafe interleavings

Promote shared object into a monitor – high-level synchronization construct– contains an implicit lock – only one thread can be

executing within the monitor at one time

Concurrent activations of monitor operations:– execute in some order without overlap– i.e., are serialized but the exact order of execution is

not defined• Note: There is an extension to monitors that allows control

over this ordering

Page 13: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Potential scenario

:MonitorQueue actor2 : …actor1 : …

pull

empty

backpop

pull

empty

back

pop

Page 14: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Another potential scenario

:MonitorQueue actor2 : …actor1 : …

pull

empty

backpop

pull

empty

back

pop

Page 15: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Thread synchronization

Definitions:– Critical section: region of code in which at most one

thread should be allowed to execute concurrently– Mutex lock: OS facility used to synchronize threads

• One and only one thread can own a lock• Thread comes to own a lock by acquiring it• A thread will block if it attempts to acquire a lock owned by

another thread

Important: Whenever you write multi-threaded programs, you must identify and protect critical sections in your code!

Page 16: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Multi-threaded programming

C++ provides no language features for thread programming– Contrast with Java, which does provide such features– In C++, threads and thread operations are provided by

standard libraries

In Unix, standard threads library is “pthreads”– Short for POSIX threads– Include files: /usr/include/pthread.h– Link library: libpthreads.a

A more object-oriented solution is the ACE library, built atop pthreads

Page 17: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Primitives for using mutex locks

ACE_Thread_Mutex: type used to declare a lock

acquire: acquires a lock, blocking if lock owned by another thread

release: releases a lock, so that other threads may acquire it

Page 18: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Exercise

Modify the design of the Queue class to protect its critical section(s) with locks.

Page 19: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Answerclass ThreadSafeQueue { public: ThreadSafeQueue() {}

… bool pull( string& s ) { lock.acquire(); bool retval = q.empty(); if (!retval) {

s = q.back();q.pop();

} lock.release(); return retval; }

protected:ACE_Thread_Mutex lock;queue<string> q;

};

Page 20: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Monitor synchronization

Defn: Monitor is an object whose methods may not be executed by multiple threads concurrently

Example:– Let o be a monitor that provides the operation:

void foo()

– Suppose threads T1 and T2 invoke o.foo() at nearly the same time

– One thread (e.g., T1) will be allowed to “enter the monitor”; the other (e.g., T2) must wait

Most OO languages use monitor synchronization

Page 21: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

The monitor-object pattern

Standard pattern for making instances of an arbitrary class behave like monitors.

Let C be the original class, and M be the (new) monitor class:– M should inherit publicly from C– M should contain a protected data member

(call it lock) of type ACE_Thread_Mutex– For each public method m of C, M should

override that method with one that acquires lock, invokes C::m and then releases lock

Page 22: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Exercise

Use the monitor-object pattern to produce an alternative version of ThreadSafeQueue by extending the original Queue class.

Page 23: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Answer

class MonitorQueue : public Queue { MonitorQueue() {} ~MonitorQueue() {}

bool pull( string& s ) {

lock.acquire(); bool retval = Queue::pull(s); lock.release(); return retval; }

protected: ACE_Thread_Mutex lock;};

Page 24: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Design uses of synchronization

Monitors used to control access to shared data by preventing two threads from executing same method simultaneously.

Provides a very primitive form of coordination among active objects

In more complex interactions, an actor might wish to “wait” for another actor to perform some task and be “signaled” when once the other actor completes the task

We refer to this as condition synchronization

Page 25: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example

Suppose we are implementing a web server that accepts incoming network connections containing http requests and processes these requests in order

Requests take some time to perform, so to be fair, we would like to “queue them up” upon arrival and dispatch them in order

Page 26: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example interaction

:Buffer reqHdlr : …netSensor : …

push

empty

handle

push

pull

push

push

pull

empty

Page 27: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Another example interaction

:Buffer reqHdlr : …netSensor : …

push

handlepull

empty

push

push

Page 28: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Another example interaction

:Buffer reqHdlr : …netSensor : …

empty

empty

empty

empty

empty

empty

empty

empty

empty

Page 29: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Issues

Obviously, buffer needs to be a monitor

We might also like to reduce the useless work performed by reqHdlr when the buffer is empty

Likewise might wish to start dropping requests when the buffer is full

Somehow, the state of the buffer needs to affect the execution of netSensor and reqHdlr

Page 30: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Condition synchronization

Another form of synchronization that allows threads to “give up” a mutex lock and go to sleep until later notified by another thread

Page 31: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Condition variables

Objects that attempt to reify conditions or states of other objects for the purpose of synchronization

Implementation:– ACE_Condition_Thread_Mutex used to declare a

condition variable (parameterized by a lock)– wait causes invoking thread to “go to sleep” and

release the lock until such time as some other thread invokes the signal operation on the condition variable

– signal wakes one of the waiting threads, and makes it enter into contention for the lock

Page 32: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Declaration of class Buffer

class Buffer { public: Buffer(); void push( const string & ); bool pull( string& ); bool empty();

protected: queue<string> requestQ; ACE_Thread_Mutex lock; ACE_Condition_Thread_Mutex fullCond; ACE_Condition_Thread_Mutex empty;};

Page 33: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Declaration of class Buffer

class Buffer { public: Buffer(); void push( const string & ); bool pull( string& ); bool empty();

protected: queue<string> requestQ; ACE_Thread_Mutex lock; ACE_Condition_Thread_Mutex fullCond; ACE_Condition_Thread_Mutex empty;};

Declares monitor lock

Page 34: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Declaration of class Buffer

class Buffer { public: Buffer(); void push( const string & ); bool pull( string& ); bool empty();

protected: queue<string> requestQ; ACE_Thread_Mutex lock; ACE_Condition_Thread_Mutex fullCond; ACE_Condition_Thread_Mutex empty;}; Declares 2 condition

variables (full & empty)

Page 35: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example

void Buffer::push( const string & s ){ lock.acquire();

while(requestQ.full()) fullCond.wait();

requestQ.push_back(s);

if (requestQ.size() == 1) emptyCond.signal();

lock.release();}

Page 36: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example

void Buffer::push( const string & s ){ lock.acquire();

while(requestQ.full()) fullCond.wait();

requestQ.push_back(s);

if (requestQ.size() == 1) emptyCond.signal();

lock.release();}

Acquires monitor lock

Releases monitor lock

Page 37: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example

void Buffer::push( const string & s ){ lock.acquire();

while(requestQ.full()) fullCond.wait();

requestQ.push_back(s);

if (requestQ.size() == 1) emptyCond.signal();

lock.release();}

Waits signal from another thread

Page 38: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Example

void Buffer::push( const string & s ){ lock.acquire();

while(requestQ.full()) fullCond.wait();

requestQ.push_back(s);

if (requestQ.size() == 1) emptyCond.signal();

lock.release();}

Signals any thread blocked on the empty condition

Page 39: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Notes

Critically important to embed the wait of a condition variable in a loop that checks the logical negation of the condition– Reason: A significant amount of time could

pass between when waiting thread is signaled and it reacquires the lock

– Possible that the condition might no longer be true when the thread awakens

Page 40: Software Architecture and Larger System Design Issues Lecture 3: Synchronization

CSE 335: Software Design K. Stirewalt

Exercise

Design the logic for Buffer::empty so that the caller will block (go to sleep) when the buffer is empty