Blepp Flashcards
(148 cards)
Adas mechanisms (protected objects with functions, procedures and entries with guards) are not that suited to solve this memory allocation problem… Why?
Guards cannot test on parameters, leading to complicated code; double interactions, Entry families or use of requeue.
Asynchronous notification- to interrupt threads in what they are doing to communicate something, is discussed in relation to atomic actions.
Why ? Why is asynchronous notification discussed in relation to atomic actions?
When one participant detects an error *something* must be done…For those errors that may have spread to more participants already (which is all by common assumption :ref. merging of failuremodes) the other threads must be made aware of the error. The(better?faster?) alterntive to polling or waiting for the prepare To Commit is to immediately notfy - asynchronously.
Javas wait and notify (and POSIX condition variables) works in many ways similar to suspend and resume. How can these be seen as better or more high-level synchronization mechanisms?
Because they are assumed called from inside a monitor (making them uninterruptable, and making testing on conditions safe), and releases the monitor when blocking.
Designing parallel systems with message-sending is an alternative to basing the design on synchronization. Give shortly and by bullet points benefits and drawbacks of these two applied to real-time systems design.
Message based systems
more maintainable,
scale better,
makes better encapsulated modules.
not as well understood in RT context.
difficult to argue schedulability.
requires more infrastructure
and puts demands on thread model.
Better abstraction for most situations.
we leave one thread per rt demand.
synch:
scale badly,
difficult to get right.
Intuitive low level primitives.
How would you rate the names of channels:
- c, ch
- incomingMessagesChan
- udpSendChan
- notAlive
- floorChannel
- primalCh
- sendMsgCh• lightEventChan
- channel_listen
- channel_write
- to_main, from_main
- messageChan
Sverres answer:
• ’c’ and ’ch’ are great if the scope is small. (less than 2-3 lines and no nesting, says code complete - Sverre is a bit more flexible…)
- ’udpSendChan’ is the winner in Sverres book: All messages on this channels are sent on udp. I could add ’incommingMessagesChan’ to this category, understanding that incomming Messages comes from another lift/node. ’sendMsgChannel’ and ’channel_listen’ is even weaker, and at the bottom here is channel_write.
- sendMsgCh, channel_listen, channel_write: Not specific enough or too dependent on context? Of course it depends on the context and which metaphors are established in the system already.
- messageChan: No seriously: All channels conveys messages….
- notAlive, floorChannel, primalCh: No, these do not give enough, or requires massive amounts of context to be understood.
- lightEventChan: probably good
- to_main, from_main: Ok if the ’main’ functionality is well-established.
What is a deadlock ? Give an example of a deadlock with semaphores.
The classic example:
T1: wait(A); wait(B); dowork; signal(B); signal(A)
T2: wait(B); wait(A); dowork; signal(A); signal(B)
I have suggested that systems based on shared variable-based synchronization scales badly. Can you argue this more generally?
At minimum, my comments could be repeated: Nested monitor calls, inheritance anomaly.
Anyway reasoning is expected to start at maintainability:
Synchronization mechanisms are operating systems mechanisms; global entities like global variables.
Semaphores are global, the Java object lock can be reserved from the outside by a “o.synchronized ” block.
Analysing the system for deadlocks (and other race conditions) is a global analysis.
Can deadlocks and race conditions happen in a message passing system?
Yes.
for a message passing system:
How do you assure the absence of deadlocks?
To avoid circular “dependencies” I would say was the correct answer here. Look at the communication arrows; use client server pattern, turn communication arrows by buffered “I need to communicate” signals a’la Øyvind Teigs guest lecture.
Going for buffered communication is a common solution and a reasonable answer (that we do not like so much…)
There are a number of assumptions/conditions that must be true for these tests to be usable.(“The simple task model”) Which? Comment(shortly) on how realistic they are.
- Fixed set of tasks (No sporadic tasks… Not optimal but fair deal)
- Periodic tasks, known periods (Realistic)
- The threads must be independent. (Not realistic at all in an embedded system)
- Overheads, switching times can be ignored (Sometimes yes, sometimes no)
- Deadline == Period (Not optimal but Fair deal)
- Fixed Worst Case Execution Time. (Not realistic to know a tight estimate here.)
- and in addition: Rate-Monotonic Priority ordering. (our choice, so ok)
Operations for locking resources are always assumed to be atomic. Why is this so important?
Locking is often an integral part of the infrastructure allowing error handling (like in an AA) . We would like to avoid that the lock manager needs to get involved in error handling together with the action participants. (this would increase the complexity of the error handling, and possibly demand knowledge in the lock manager of the Action.)
We can prove that the deadlines in the system will be satisfied by response time analysis and utilization-based schedulability tests. Explain shortly how these two works.
Utilization: we have a formula which guarantees schedulability for N threads if the threads have rate-monotonic priorities and the sum of utilizations are less than a given number (dependent only in N).
Response time: For each thread we can calculate its worst case response time from its max execution time and the number of times it can be interrupted by higher-priority threads.
******** Both forward and backward error recovery can be generalized from single thread to multi thread systems Backward error recovery may, when generalizing to multi-thread systems give the domino effect. Explain. How can we avoid the domino effect?
Everything that looks like the “domino effect figure” is great for the first part of the question. Coordinating recovery points is the solution to the second.
How can we get «termination mode» asynchronous transfer of control in POSIX/C? What about Java(/RT Java)? And ADA?
C: Canceling of threads or the setjmp/longjmp trick…
RT Java: AsynchronouslyInterrupted Exception (Java: canceling of threads.)
Ada: select-then-abort
Inheritance Anomaly is a potential problem when we imagine inheriting from a class (in an object oriented setting likeJava orc++)where any methods synchronize. Explain where the problem lies.
For objectoriented inheritance we can add to or override any features of the base class. It is not given (and is in fact false) that extending synchronization by the same mechanisms will work at all. The interaction between synchronication code in parent and child classes becomes complex, and even in some cases the base class synchronization code becomes impossible to tweek into meaningful child class synchronization... Any example will of course also do.
List the techniques you would use together with short explanations of how they contribute to making the system fault tolerant.
System 1 is a multi threaded system to be written in C, using semaphores to protect shared resources. The size of the system and the interactions between the threads are such that you see no way of guaranteeing the complete absence of deadlocks. The system should be made tolerant to deadlocks.
The task here is to handle the fact that deadlocks happen - that is; detect deadlocks and then loosen the knot in some way.
- Detection: Watchdog is a simple way. Introducing a lock manager that detects deadlocks is another.
- Handling: We need to introduce “preemption of resources” in some manner aborting/restarting either threads or tasks. The problem here is to make this preemption without leaving the system in an inconsistent state. I would say structuring the systems functionality into atomic actions/transactions is the feasible way
Explain the terms “backward error recovery” and “recovery points”.
Backward error recovery: If an error is detected we go back to a previous, known-to-be-consistent, state. Recovery point: One of these known-to-be-consistent, states. Typically a complete snapshot of the programs state.
We imagine a classical real-time system with threads that synchronize using semaphores: How, typically, is it decided which thread gets to run (to achieve the goals in the previous question)?
The threads are classified by priorities; The runnable thread with the highest priority gets to run.
How can the domino effect be avoided?
Coordinate the making of the recovery points, typically when entering an atomic action.
1 count++;
2 if(count==3){ // All here, signal the others, reset, continue
3 signal(A);
4 signal(A);
5 count = 0;
6 }else{ // Not everyone have arrived, must wait
7 wait(A); }
This code has at least one problem: Which?
If one thread gets interrupted after the count increment, then the last thread arriving might reset count before it gets to test on it. There is a race condition connected to the if that will lead to more threads executing the true-part rather than the false-part. These two are the most important bugs to find.
Also there is a potential problem with the count variable itself if count++ is not atomic. Reusability of the barrier is also an issue; is the barrier properly prepared for the next time the barrier is used? If a thread tries to enter again before the others have left?
Give some(3-4?) principles guiding variable naming.
Sverres favourites are:
• “Does the name fully and accurately describe what the variable represents?” • “Is the name long enough that you don’t have to puzzle it out?”
- “Does the convention distinguish among local, class, and global data? ”and“ Does the convention distinguish among type names, named constants, enumerated types, and variables? ”.Sverre likes this; A name could easily signal a lot of its ’context’.
- “Are all words abbreviated consistently?”. Sverre: More generally (not only abbreviations): consistence on all levels –> guessability!
What is “Priority Inversion” ?
That one task ends up waiting for a lower prioritytask. This may happen when they share a resource that the lowpriority task holds.
It is ok if the student also explains unbounded priority inversion, but these two should not be confused.
Comment on the danger for starvation regarding the memory allocation task over. Suggest a strategy for memory allocation to waiting threads that does not have this problem.
We have the choice here between either blocking threads “unnecessary” - they are asking for little enough memory that the request could have been fulfilled or starving the big requests.
First come, first serve is a strategy that avoids this starvation (the price is blocking smaller requests unecessary…).