310 likes | 414 Views
COEN 171 - Concurrency and Exceptions. Coroutines Physical and logical concurrency Synchronization semaphores monitors message passing Ada tasking Java threads Producer/consumer examples Exception handling. Coroutines. Relax restriction on subprograms of single entry point
E N D
COEN 171 - Concurrency and Exceptions • Coroutines • Physical and logical concurrency • Synchronization • semaphores • monitors • message passing • Ada tasking • Java threads • Producer/consumer examples • Exception handling
Coroutines • Relax restriction on subprograms of single entry point • but only one is executing at any time • Provided by Simula 67, Modula-2, BLISS, INTERLISP • Really like a subroutine with • multiple entry points • which is valid controlled by coroutine • means of maintaining state between activations • static local variables • Invoke coroutine with resume statement • often using variable to specify which coroutine to resume • Master Unit creates family of coroutines • initialization segment executes for each as created • master resumes one coroutine, which invokes others • control returns to master when last coroutine ends
Coroutines (continued) A Resume A B Master Resume B Resume A Resume B Resume A Classic example of coroutine structures
Coroutines (continued) A Resume A B 1st time Master Resume B Resume A other times Realistic example of coroutine structures Producer / Consumer
Coroutines (continued) • Some languages allow coroutine creation dynamically, others only allow static creation • If dynamically created, memory allocation a problem • coroutines don’t follow stack discipline of subprograms • string ARs for coroutines on linked list from AR of master unit • Coroutines can be • full control statements in the language • provided as an add-on in a library
Concurrency • Concurrency comes in several different flavors • Instruction level • Statement level • Unit level • Primarily concentrate discussion here • Program level • Unit level concurrency relaxes restriction on subprograms that invoking unit must suspend while invoked unit executes • also doesn’t satisfy stack discipline for subprogram execution
Concurrency (continued) • Unit of concurrency is the task • task is program unit with its own thread of control (path through program statements) • task may be • defined like subprogram • may have task type, and declaring variables of that type creates a task instance • task may be started • implicitly (by flowing into program unit where it was declared) • explicitly • tasks may be • New (just created) • Ready (or runnable) • Running • Blocked • Dead • task is live if it continues to make progress towards completion
Concurrency (continued) • Physical concurrency involves multiple hardware processors • simplest case 1 per task • issues of shared memory vs. local memory • Logical concurrency involves only a single hardware processor, but task execution interleaved so it seems like concurrent execution • Coroutines provide quasi concurrency • Concurrency interesting since • logical model of some problem domains • producer / consumer • also issues of physical concurrency more common • parallel processing architectures
Synchronization • Two or more tasks have no predefined order for execution yet often have to share “resources” • implies need for synchronization of tasks • If tasks know about each other, can use cooperation synchronization • tasks are written to voluntarily control correct order of execution • Other process at stage I need? No, wait; yes, proceed • If no knowledge of other tasks, must use competition synchronization • to ensure mutually exclusive access to shared resource fetch A; A := X; store A fetch A; A := Y; store A
Implementing Synchronization • Binary semaphore • variable with initial value of 1 • wait operation: if semaphore is 1, set to 0 and continue, else queue • signal operation: if something in queue, remove first and allow to continue, else semaphore := 1 • Access to shared resource is • wait(sema); use resource; signal (sema) • requires discipline and honorable intentions on part of all programmers! • General semaphore starts with initial value > 1, signal increments semaphore by 1 • implies more than one resource to share • Wait and signal are atomic operations (uninterruptible) • hardware instructions or in kernel • Any use of semaphores assumes error-free voluntary use of semaphore
Synchronization (continued) • Monitors (Concurrent Pascal, Modula, Mesa) are way to synchronize without depending on programmers • think of as fence around resource • access ports in fence provide legal operations on resource • only 1 access point active at any time • all calls made when some port active are queued • Competition synchronization is guaranteed • Cooperation synchronization must still be provided by the programmer insert Data Structure remove
Synchronization (continued) • Message passing is another way to synchronize • tasks send messages to each other to inform of progress or request actions • Phone model (synchronous) • sender places call, waits until receiver picks it up • this connection called rendezvous • in simplest form, sender continues after rendezvous • in alternative form, sender waits for receiver to complete processing before continuing • whole “connect time” is rendezvous • similar to “remote procedure call”
Ada 83 Tasking Model • Most advanced of any production language, but still controversial • message passing (phone) model • Tasks have two parts • specification indicates • name of task • entry points (places where task will accept messages) • include parameters if desired • not required unless intertask communication needed • outside entity calls entry point, suspends until rendezvous • body includes • one accept statement for each entry point • accept <entry name> <parameters> do <clause body> end; • clause body is what gets executed during rendezvous • body execution suspends when reach accept statement if no call from outside waiting for corresponding entry point • Become active at begin of declaring block
Ada 83 Tasking Model (continued) • Can provide several accepts by placing in select statement (non-deterministically execute one) • can also attach guard to any accept • select • accept E1 do • end E1; • or • when SomeCondition => accept E2 do • end E2; • end select; • Guarded accept clauses implement cooperation synch. • Tasks may also be types and can even be dynamically created using new and assigning value to a pointer • task type Filter is entry E end Filter; • type filter_task is access filter; filter_2: filter_task; • filter_2 := new filter; filter_2.E;
Ada 83 Tasking Model (continued) • Termination • If task hasn’t created dependent tasks, it terminates when complete • If task has created dependent tasks, doesn’t terminate until all dependents have terminated • Select statements can have terminate clauses • Selected when no accept clauses are open
Synchronization (continued again) • Mailbox model (asynchronous) • task 1 sends request to task 2, then proceeds • task 2 retrieves request when able and operates on it • mailboxes can be • 1 - 1 (sender specifies receiver, receiver specifies sender) • many - 1 (sender specifies receiver, receiver takes any messages waiting regardless of source) • many - many (no specification of particular receiver or sender) • note model doesn’t require notification of completion of request • but “return receipt” sometimes included • Not available in Ada 83, but exists in Ada 95
Java Threads • Concurrent units in Java are run methods • Part of Thread class • Subclasses inherit and override run method from Thread • JVM provides a priority queue scheduler, typically implemented as round-robin time slice • Thread class includes several methods of relevance to concurrency besides run • start, which calls run and control returns immediately to caller • Means caller and run are executing simultaneously • yield, which stops execution and puts thread in ready queue • sleep, which suspends thread and blocks it for specified time • resume, which restarts suspended thread • stop, which kills thread • setPriority and getPriority change or report thread’s priority compared to other threads
Java Threads (continued) • Competition synchronization • Synchronized modifier for methods • Means method must be run to completion before any other methods for same object can run • Other methods that want to run are queued, started when running method stops • Synchronized statement allows synchronization on part of a method • <expression> must evaluate to object, object is locked for duration of statement Synchronized (<expression>) statement
Java Threads (continued) • Cooperation synchronization • All classes have wait and notify methods • Part of root class, Object • Must be used inside synchronized method • Wait is called inside a loop testing cooperation condition • Places thread in a queue if condition is not true • Notify removes one waiting thread so it can proceed try { while (! theCondition) wait(); <do whatever needed after condition is true> } catch (InterruptedException someProblem) { …}
When to Choose Which Method • Need monitor or message passing for competition synchronization • On shared memory systems, message passing and monitors provide roughly similar performance • On local memory distributed systems, message passing is best • Can use message passing to implement other methods task BINARY_SEMAPHORE IS entry WAIT; entry SIGNAL; end BINARY_SEMAPHORE; task body BINARY_SEMAPHORE IS begin loop accept WAIT; accept SIGNAL; end loop; end BINARY_SEMAPHORE;
Exception Handling • Some languages provide special facilities for dealing with run-time errors and other special events • PL/I, CLU, Ada, Mesa, ML, C++, Java • events like divide by zero, running out of memory, etc. • Events are called exceptions, and facilities are called exception handlers • exceptions are said to be raised • these are more elaborate than simple I/O error handling capabilities found in many primitive languages • BASIC, FORTRAN • Exceptions are synchronous events, unlike interrupts that are asynchronous events • exceptions occur at predictable points during execution • Languages with exception handling also usually provide mechanism for user-defined exceptions
Exception Handling (continued) • Alternatives to exception handling include • Use the return value of a subprogram (or an auxiliary status parameter) to indicate performance status (C) • Pass a label parameter to all subprograms and return to label on error (FORTRAN) • Pass an exception handling subprogram to all subprograms • Built-in exception handling has advantages • Error detection code is tedious to write and clutters program, hindering readability • Exception propagation allows error handling code to be reused
Exception Design Issues • How are exception handlers specified, and what is scope? • usually specified with reserved word • PL/I: on <ex. name> Ada: exception when <ex. name> => • modern trend is to have exception handlers appear at end of block • scope is usually program unit in which defined • How does the language determine which handler to invoke when exception occurs • PL/I used dynamic • most recently executed on statement for that exception • other languages use static scope • specifying handler in program unit applies for entire scope of unit
Exception Design Issues (continued) • What if no handler in effect for unit where exception occurs? • usually propagate • terminate unit • raise same exception in unit that called excepting unit • continue until find handler or reach top level (when program terminates!) • NOTE that this is a dynamic activity, even if exception handler scope is static!! • some languages allow defining a default exception handler • Ada: exception when others => handles any exception not otherwise explicitly listed
Exception Design Issues (continued) • Where does execution continue after exception handler finishes? • 1. terminate program unit that caused exception and return to calling unit • 2. terminate program unit that caused exception and raise same exception in calling unit • propagate one level even if handled • 3. resume execution of program unit that raised exception, retrying statement when exception occurred • 4. resume execution of program unit that raised exception with statement after one where exception occurred • Are there built-in exceptions, or only user-defined? • Are there system provided default handlers? • Can exceptions be disabled?
PL/I • First widely used language with exception handling • Conditions could be built-in • 22 defined • Some always enabled, others enabled or disabled by default but program could change • Binding of handlers to exceptions is dynamic • Define handler by ON <condition> begin; … end; • Effective within block where it appears • ON is an executable statement • Continuation could be • Terminate program • Return control to statement where exception was raised • User-defined exceptions could go to any labled statement in program
PL/I (continued) • User-defined exceptions created by declaring name • CONDITION foo • Can override built-in handlers • Exceptions raised by SIGNAL statement • Exceptions enabled/disabled by program unit, block, statement • (foo, NOSUBSCRIPTRANGE): • Evaluation • Dynamic binding of handlers makes programs difficult to read and debug • Continuation rules confusing
Ada • Exceptions are statically scoped • Apply to subprogram body, package body, task or block • Handlers always are placed at the end of the block or unit to which they apply • Propagation (if not handled locally) depends on kind of unit • Procedures propagate to calling program unit • Blocks are “parameterless procedures” and propagate to point after the block • Packages propagate to declaration section of unit that declared package • Tasks don’t propagate, just terminate • Continuation • Any unit propagating exception is terminated • Since exceptions are always at the end of the unit, if exception handled unit is also terminated
Ada (continued) • Five built-in exceptions • Some may be disabled • Raise statement invokes exception • General form is begin <code body> exception when name1 => <handler code> when name2 => <handler code> when others => <default handler code> end;
C++ • Exception handling added to C++ in 1990 • Only user-defined exceptions • Raised by throw <expression> • Can’t be disabled • Propagated dynamically to calling unit • If handled, continued at first statement after try construct • General form Try { <code body> Catch (parameter) { … } linear search for handler Catch (parameter) { … }if parameter … , default
Java • Design much more consistent with OO philosophy • All exceptions descend from Throwable class • Error subclass thrown by JVM, not handled by user • Exception subclass has two further predefined subclasses (IOException and RuntimeException) • Uses try catch syntax • Every parameter must be an object descended from Throwable • Exception bound to first handler with a parameter of same class as thrown or an ancestor of that class • Propagate to • Containing try construct • Method’s caller • Methods must list all checked exceptions (those not descendents of Error and RuntimeException) they may throw, if not handled internally • Finally clause allows cleanup, must be executed after any handler