460 likes | 474 Views
This lecture covers advanced state modeling and analysis topics, including modeling concurrent behaviors using UML state diagrams. It also explores additional topics related to software architecture and larger system design issues. The course outline includes foundational object-oriented concepts and synthetic concepts.
E N D
Software Architecture and Larger System Design Issues Lecture 6: Advanced state modeling/analysis Topics: Modeling/analyzing concurrent behaviors using UML state diagrams Chapter 6 in Blaha and Rumbaugh Additional topics not in the Blaha/Rumbaugh book CSE 335: Software Design
Outline of course topics Foundational OO concepts Synthetic concepts Software architecture and larger design issues: • Strategic design decisions that influence a host of smaller, more tactical design decisions • E.g., policy for persistence of data in long-running system • E.g., allocating functionality to a single, centralized system vs. distributing functionality among a collection of communicating hosts • Often involve a major capital investment • Source of both risk and opportunity • Require lots of a priori modeling and analysis • Focus: Design issues related to concurrent and distributed systems Software process issues CSE 335: Software Design
Analytical models of behavior Thus far, the models we have employed have proved useful for • documentation/explanation • “roughing out” a design prior to implementation Still, they are not very rigorous: • E.g., sequence diagrams depict only one scenario of interaction among objects • Not good for reasoning about space of possible behaviors Such reasoning requires more formal and complete models of behavior CSE 335: Software Design
State diagrams Useful for modeling “space of behaviors” of an object or a system of interacting objects Requires: • Identifying and naming the conceptual “states” that an object might be in, and • Conceivable transitions among those states and the events (and/or conditions) that trigger (and/or guard) these transitions Concurrent compositions of state diagrams can be “executed” to expose anomalous behaviors CSE 335: Software Design
Communication among concurrent state machines More interesting applications involve interaction (explicit communication) among state machines Examples: • Active client objects interacting with a shared queue • Sensor object notifying a software controller • Perhaps even an object invoking a method on another UML provides send actions by which one machine may signal another CSE 335: Software Design
Simple example: Client using a queue c1 : Client q : Queue System comprises two objects Each object modeled by a state machine System state at any time is the pair (state of c1, state of q) CSE 335: Software Design
Modeling method invocations Given state machines for two objects C and S, where C is the client and S the supplier of a method m Model call and return of m as separate signals C sends the call signal to S and then enters a waiting state, which is exited upon reception of a return signal from S CSE 335: Software Design
Example Client ... /send S.mCall(this, ...) mRet(...) Waiting Supplier mCall(caller, ...) ... /send caller.mRet(...) Processing Body of M CSE 335: Software Design
Exercise Develop state models for a simple client and a queue, assuming: • class Client does nothing but repeatedly pull items off of the queue • class Queue provides an operation pull, which is implemented by calling empty, back, and pop on a private data member of type queue<string> CSE 335: Software Design
Example: Client model Client / send q.pullCall(this) Initializing Waiting pullReturn(b,s) do / processString(b,s) CSE 335: Software Design
Example: Shared queue Queue ProcessingPullCall Idle pullCall(caller) [!q.empty()] Checking [q.empty()] / send caller.pullRet(false,empty) Empty / send caller.pullRet(true,s) NotEmpty do / s := q.back CSE 335: Software Design
c1 : Client c2 : Client Recall: Two active clients sharing a queue q q q : Queue CSE 335: Software Design
Question Do our state diagrams for classes Client and Queue accurately model the behaviors of active clients acting on a shared queue? CSE 335: Software Design
Question Do our state diagrams for classes Client and Queue accurately model the behaviors of active clients acting on a shared queue? Answer really depends upon the “semantics” of event handling among concurrent state machines CSE 335: Software Design
Semantics of parallel composition Multiple interpretations: • Concurrent regions execute independently • What happens if transitions in different regions are triggered by same event? • Do both execute simultaneously? Does one “consume” the event to the exclusion of the other? Does each get a separate “copy” of the event? • Concurrent regions communicate with one another, synchronizing on common events • Regions can only proceed when all are ready to proceed • Regions transfer data values during a concurrent transition • Do we distinguish internal and external events? CSE 335: Software Design
UML 2.0 Interpretation: Asynchronous events run to completion Run-to-completion semantics: • State machine processes one event at a time and finishes all consequences of that event before processing another event • Events do not interact with one another during processing Event pool: • Where new events for an object are stored until object is ready to process them • No event ordering assumed in the pool CSE 335: Software Design
c1’s pool: c2’s pool: Client Client / send q.pullCall(this) / send q.pullCall(this) Initializing Waiting Initializing Waiting pullReturn(b,s) pullReturn(b,s) do / processString(b,s) do / processString(b,s) Queue q’s pool: ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] / send caller.pullRet(false,empty) Empty / send caller.pullRet(true,s) NotEmpty do / s := q.back CSE 335: Software Design
c1’s pool: c2’s pool: Client Client / send q.pullCall(this) / send q.pullCall(this) Initializing Waiting Initializing Waiting pullReturn(b,s) pullReturn(b,s) do / processString(b,s) do / processString(b,s) Queue q’s pool: ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] / send caller.pullRet(false,empty) Empty / send caller.pullRet(true,s) NotEmpty do / s := q.back CSE 335: Software Design
c1’s pool: c2’s pool: Client Client / send q.pullCall(this) / send q.pullCall(this) Initializing Waiting Initializing Waiting pullReturn(b,s) pullReturn(b,s) do / processString(b,s) do / processString(b,s) Queue q’s pool: ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] / send caller.pullRet(false,empty) Empty / send caller.pullRet(true,s) NotEmpty do / s := q.back CSE 335: Software Design
c1’s pool: c2’s pool: Client Client / send q.pullCall(this) / send q.pullCall(this) Initializing Waiting Initializing Waiting pullReturn(b,s) pullReturn(b,s) do / processString(b,s) do / processString(b,s) Queue q’s pool: pullCall(c1) ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] / send caller.pullRet(false,empty) Empty / send caller.pullRet(true,s) NotEmpty do / s := q.back CSE 335: Software Design
c1’s pool: c2’s pool: Client Client / send q.pullCall(this) / send q.pullCall(this) Initializing Waiting Initializing Waiting pullReturn(b,s) pullReturn(b,s) do / processString(b,s) do / processString(b,s) Queue q’s pool: ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] / send caller.pullRet(false,empty) Empty / send caller.pullRet(true,s) NotEmpty do / s := q.back CSE 335: Software Design
c1’s pool: c2’s pool: Client Client / send q.pullCall(this) / send q.pullCall(this) Initializing Waiting Initializing Waiting pullReturn(b,s) pullReturn(b,s) do / processString(b,s) do / processString(b,s) Queue q’s pool: pullCall(c2) ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] / send caller.pullRet(false,empty) Empty / send caller.pullRet(true,s) NotEmpty do / s := q.back CSE 335: Software Design
c1’s pool: c2’s pool: Client Client / send q.pullCall(this) / send q.pullCall(this) Initializing Waiting Initializing Waiting pullReturn(b,s) pullReturn(b,s) do / processString(b,s) do / processString(b,s) Queue q’s pool: pullCall(c2) ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] / send caller.pullRet(false,empty) Empty / send caller.pullRet(true,s) NotEmpty do / s := q.back CSE 335: Software Design
c1’s pool: pullRet(false, empty) c2’s pool: Client Client / send q.pullCall(this) / send q.pullCall(this) Initializing Waiting Initializing Waiting pullReturn(b,s) pullReturn(b,s) do / processString(b,s) do / processString(b,s) Queue q’s pool: pullCall(c2) ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] / send caller.pullRet(false,empty) Empty / send caller.pullRet(true,s) NotEmpty do / s := q.back CSE 335: Software Design
Observations Modeling method invocations as asynchronous events which are placed in a pool: • Requests for service on an object: • “buffered up” on arrival • dispatched when the object is ready to handle them • Natural interpretation for how an active object can be invoked • Makes passive objects appear to execute with “monitor semantics” CSE 335: Software Design
Observations (continued) In real programs, not every passive object is (or should be) a monitor: • There is some expense associated with acquiring more locks than are needed to synchronize threads • We often want to analyze a system to choose which passive objects should be monitors. How could we use state-machine models for this purpose? CSE 335: Software Design
More precisely… How could we model the shared queue as a state machine that admits the behaviors on the following slide? CSE 335: Software Design
Example c1 : … q :Queue c2 : … pull empty pull empty back pop back pop CSE 335: Software Design
Answer Duplicate an object’s state model with one copy for each system thread Note: This will need to be done for each passive object, and it will potentially cause the number of states in the system to grow out of control CSE 335: Software Design
ProcessingPullCall ProcessingPullCall pullCall(caller) pullCall(caller) [!q.empty()] [!q.empty()] Idle Idle Checking Checking [q.empty()] [q.empty()] Empty Empty / send caller.pullRet(…) / send caller.pullRet(…) NotEmpty do / s := q.back NotEmpty do / s := q.back / send caller.pullRet(true,s) / send caller.pullRet(true,s) Example: Shared queue CSE 335: Software Design
ProcessingPullCall ProcessingPullCall pullCall(caller) pullCall(caller) [!q.empty()] [!q.empty()] Idle Checking Idle Checking [q.empty()] [q.empty()] Empty Empty / send caller.pullRet(…) / send caller.pullRet(…) NotEmpty do / s := q.back NotEmpty do / s := q.back / send caller.pullRet(true,s) / send caller.pullRet(true,s) Initial state of shared queue CSE 335: Software Design
ProcessingPullCall ProcessingPullCall pullCall(caller) pullCall(caller) [!q.empty()] [!q.empty()] Idle Checking Idle Checking [q.empty()] [q.empty()] Empty Empty / send caller.pullRet(…) / send caller.pullRet(…) NotEmpty do / s := q.back NotEmpty do / s := q.back / send caller.pullRet(true,s) / send caller.pullRet(true,s) Client c1 invokes pull… CSE 335: Software Design
ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] Empty / send caller.pullRet(…) NotEmpty do / s := q.back / send caller.pullRet(true,s) Queue is not empty… ProcessingPullCall pullCall(caller) [!q.empty()] Idle Checking [q.empty()] Empty / send caller.pullRet(…) NotEmpty do / s := q.back / send caller.pullRet(true,s) CSE 335: Software Design
ProcessingPullCall ProcessingPullCall pullCall(caller) pullCall(caller) [!q.empty()] [!q.empty()] Idle Checking Idle Checking [q.empty()] [q.empty()] Empty Empty / send caller.pullRet(…) / send caller.pullRet(…) NotEmpty do / s := q.back NotEmpty do / s := q.back / send caller.pullRet(true,s) / send caller.pullRet(true,s) At this point, context switch and client c2 invokes pull… CSE 335: Software Design
ProcessingPullCall ProcessingPullCall pullCall(caller) pullCall(caller) [!q.empty()] [!q.empty()] Idle Checking Idle Checking [q.empty()] [q.empty()] Empty Empty / send caller.pullRet(…) / send caller.pullRet(…) NotEmpty do / s := q.back NotEmpty do / s := q.back / send caller.pullRet(true,s) / send caller.pullRet(true,s) C1 has yet to pop queue; so c2’s check for empty fails CSE 335: Software Design
ProcessingPullCall ProcessingPullCall pullCall(caller) pullCall(caller) [!q.empty()] [!q.empty()] Idle Checking Idle Checking [q.empty()] [q.empty()] Empty Empty / send caller.pullRet(…) / send caller.pullRet(…) NotEmpty do / s := q.back NotEmpty do / s := q.back / send caller.pullRet(true,s) / send caller.pullRet(true,s) Bad state! If queue contained only one element… CSE 335: Software Design
Question Assuming this interpretation of passive objects, how would we model the promotion of shared queue to a monitor? CSE 335: Software Design
Question Assuming this interpretation of passive objects, how would we model the promotion of shared queue to a monitor? Answer: Two ways • Model the lock explicitly as another state machine • Use only a single state machine model for queue rather than replicating per thread CSE 335: Software Design
Model checking Technique for exhaustively and automatically analyzing finite-state models to find “bad states” • Bad states are specified in a temporal logic or some other declarative notation Lots of tools that can be used for this purpose: • FSP, SMV, Spin, etc If you are designing concurrent software, want to learn how to use these tools CSE 335: Software Design
Wrap-up: Use of models In this course, we have now used models for many purposes: • Documentation and demonstration of characteristics of a complex design • Means for understanding the requirements of a system to be built • Analysis for tricky concurrency properties CSE 335: Software Design
Question What does it mean to transition out of a concurrent composite state? CSE 335: Software Design
Question What does it mean to transition out of a concurrent composite state? Two possible answers: • transition awaits completion of all concurrent activities • transition acts immediately, terminating all concurrent activities CSE 335: Software Design
Example: Bridge game PlayingRubber Not Vulnerable N-S wins rubber ns-game ns-game Vulnerable Not Vulnerable E-W wins rubber ew-game ew-game Vulnerable Note: Transition out of PlayingRubber by one concurrent activity terminates the other CSE 335: Software Design
Example: Cash dispenser Emitting do/ dispenseCash ready SetUp Complete do/ ejectCard Note: Will not transition out of Emitting until after completion of all concurrent activities CSE 335: Software Design
Recall: State explosion problem Number of states in a system with multiple, orthogonal, behaviors grows exponentially (product of number of states of each feature) Major impediment to understanding: • Impossible to visualize in any meaningful way • Requires the use of analysis tools to verify properties Managing state explosion: • Concurrent state machines • Each object in a system modeled as a state machine • Object state machine runs concurrently with those of other objects • Concurrent composite states • Separates one machine can into orthogonal submachines CSE 335: Software Design
Example: Concurrent composite state Automobile Temperature control TempOn pushAir Cooling pushTCOff TempOff pushHeat pushAir Heating pushHeat Rear defroster Radio control pushRD pushRad RDOff RDOn RadOff RadOn pushRD pushRad CSE 335: Software Design