1 / 17

Lecture 6:

Lecture 6:. Monitors & Semaphores. Monitor. Monitor Contains data and procedures needed to allocate shared resources Accessible only within the monitor No way for threads outside monitor to access monitor data Resource allocation using Monitors

cianna
Download Presentation

Lecture 6:

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Lecture 6: Monitors & Semaphores

  2. Monitor • Monitor • Contains data and procedures needed to allocate shared resources • Accessible only within the monitor • No way for threads outside monitor to access monitor data • Resource allocation using Monitors • Thread must call monitor entry routine • Mutual exclusion is rigidly enforced at monitor boundary • A thread that tries to enter monitor when it is in use must wait Operating Systems - Deitel & Associates - 2004

  3. lock( ) vs. monitor( ) Both lock( ) and monitor( ) are methods of enforcing mutual exclusion in modern programming languages such as C# and Java. In the .NET environment, lock( ) is preferred since it manages the thread queue. Like the lock keyword, monitors prevent blocks of code from simultaneous execution by multiple threads. The Enter method allows one and only one thread to proceed; all other threads are blocked until the executing thread calls Exit. This is just like using the lock keyword. In fact, the lock keyword is implemented with the Monitor class. Using the lock is generally preferred over using the Monitor class directly, both because lock is more concise, and because lock ensures that the underlying monitor is released, even if the protected code throws an exception. This is accomplished with the finally keyword, which executes its associated code block regardless of whether an exception is thrown. http://msdn.microsoft.com/en-us/library/ms173179%28VS.80%29.aspx

  4. Multi-Threaded Demo no Monitor using System; using System.Threading; namespace monitor_demo_02 { publicclassTest { staticint count = 0; staticvoid Main() { ThreadStart job = newThreadStart(ThreadJob); Thread thread = newThread(job); thread.Start(); for (int i = 0; i < 5; i++) { int tmp = count; Console.WriteLine("Read count={0}", tmp); Thread.Sleep(50); tmp++; Console.WriteLine("Incremented tmp to {0}", tmp); Thread.Sleep(20); count = tmp; Console.WriteLine("Written count={0}", tmp); Thread.Sleep(30); } thread.Join(); Console.WriteLine("Final count: {0}", count); Console.ReadKey(); } http://www.yoda.arachsys.com/csharp/multithreading.html

  5. Multi-Threaded Demo - concluded staticvoid ThreadJob() { for (int i = 0; i < 5; i++) { int tmp = count; Console.WriteLine("\t\t\t\tRead count={0}", tmp); Thread.Sleep(20); tmp++; Console.WriteLine("\t\t\t\tIncremented tmp to {0}", tmp); Thread.Sleep(10); count = tmp; Console.WriteLine("\t\t\t\tWritten count={0}", tmp); Thread.Sleep(40); } } } }

  6. Multi-Threaded Sample Output Read count=0 Read count=0 Incremented tmp to 1 Written count=1 Incremented tmp to 1 Written count=1 Read count=1 Incremented tmp to 2 Read count=1 Written count=2 Read count=2 Incremented tmp to 2 Incremented tmp to 3 Written count=2 Written count=3 Read count=3 Read count=3 Incremented tmp to 4 Written count=4 Incremented tmp to 4 Written count=4 Read count=4 Read count=4 Incremented tmp to 5 Written count=5 Incremented tmp to 5 Written count=5 Read count=5 Incremented tmp to 6 Written count=6 Final count: 6

  7. Monitor Demo using System; using System.Threading; namespace monitor_demo_01 { publicclassTest { staticint count = 0; staticreadonlyobject countLock = newobject(); staticvoid Main() { ThreadStart job = newThreadStart(ThreadJob); Thread thread = newThread(job); thread.Start(); for (int i = 0; i < 5; i++) { Monitor.Enter(countLock); int tmp = count; Console.WriteLine("Read count={0}", tmp); Thread.Sleep(50); tmp++; Console.WriteLine("Incremented tmp to {0}", tmp); Thread.Sleep(20); count = tmp; Console.WriteLine("Written count={0}", tmp); Monitor.Exit(countLock); Thread.Sleep(30); } thread.Join(); Console.WriteLine("Final count: {0}", count); Console.ReadKey(); }

  8. Monitor Demo - concluded staticvoid ThreadJob() { for (int i = 0; i < 5; i++) { Monitor.Enter(countLock); int tmp = count; Console.WriteLine("\t\t\t\tRead count={0}", tmp); Thread.Sleep(20); tmp++; Console.WriteLine("\t\t\t\tIncremented tmp to {0}", tmp); Thread.Sleep(10); count = tmp; Console.WriteLine("\t\t\t\tWritten count={0}", tmp); Monitor.Exit(countLock); Thread.Sleep(40); } } } }

  9. Monitor Demo Sample Output Read count=0 Incremented tmp to 1 Written count=1 Read count=1 Incremented tmp to 2 Written count=2 Read count=2 Incremented tmp to 3 Written count=3 Read count=3 Incremented tmp to 4 Written count=4 Read count=4 Incremented tmp to 5 Written count=5 Read count=5 Incremented tmp to 6 Written count=6 Read count=6 Incremented tmp to 7 Written count=7 Read count=7 Incremented tmp to 8 Written count=8 Read count=8 Incremented tmp to 9 Written count=9 Read count=9 Incremented tmp to 10 Written count=10 Final count: 10

  10. Semaphores • Semaphores • Software construct that can be used to enforce mutual exclusion • Contains a protected variable • Can be accessed only via wait and signal commands • Also called P and V operations, respectively

  11. Binary Semaphore • Binary semaphore: allow only one thread in its critical section at any time... • Wait operation • If no threads are waiting, allow thread into its critical section • Decrement protected variable (to 0 in this case) • Otherwise place in waiting queue • Signal operation • Indicate that thread is outside its critical section • Increment protected variable (from 0 to 1) • A waiting thread (if there is one) may now enter

  12. Counting Semaphores • Counting semaphores • Initialized with values greater than one • Can be used to control access to a pool of identical resources • Decrement the semaphore’s counter when taking resource from pool • Increment the semaphore’s counter when returning it to pool • If no resources are available, thread is blocked until a resource becomes available

  13. Semaphores A semaphore is a protected variable whose value can be accessed and altered only by the operations P( ) and V( ) and an initialization operation SemaphoreInit( ). Binary semaphores can have values true or false while counting semaphores can have non-negative integer values. function P(S:semaphore) if S>0 then S:=S-1; else wait_for(S); end if; end P; function V(S:semaphore) ifwaiting_for(S)then release_for(S); else S:=S+1; end if; end V; wait_for(S) adds the process calling P(S) to a queue. waiting_for(S) is a boolean function that checks to see if the queue is empty. release_for(S) releases the process waiting at the front of the queue.

  14. Using Semaphores: Mutual Exclusion procedureP2is begin whiletruedo begin stuff; P(active); critical_region; V(active); end; endP2; beginexample_one semaphore_init(active,1); parbegin P1; P2; parend; endexample_one; programexample_one is active : semaphore; procedureP1is begin whiletruedo begin stuff; P(active); critical_region; V(active); end; endP1; The semaphore active is set to one (1) and acts to control the process’s access to its critical section.

  15. Using Semaphores: Producer-Consumer Interprocess communication occurs when one process passes data to another process. This is more complex than a procedure call with parameter passing since the two processes do not necessarily share the same address space. The processes must be synchronized which means that the data transfer must occur in the proper time sequence. procedureproduceris nextvalue : integer; begin whiletruedobegin calculate(nextvalue); P(access_numbuffer); numbuffer:=nextvalue; V(access_numbuffer); V(numbuffer_loaded); end; endproducer; procedureconsumeris nextvalue : integer; begin whiletruedobegin P(numbuffer_loaded); P(access_numbuffer); nextvalue:=numbuffer; V(access_numbuffer); make_use_of(nextvalue); end; endconsumer;

  16. Mutual Exclusion with Test-and-Set When the computer hardware can be used to support the enforcement of mutual exclusion, the complexity of the resulting software is greatly reduced. The indivisible instruction testandset(a,b)reads the value of a boolean b, copies it into a and then sets b to true all within the span of a single uninterruptible instruction. procedureP2 no_P2 : boolean; begin whiletruedo begin no_P2:=true; whileno_P2do testandset(no_P2,go); critical_region; go:=false; other_stuff; end; endP2; procedureP1 no_P1 : boolean; begin whiletruedo begin no_P1:=true; whileno_P1do testandset(no_P1,go); critical_region; go:=false; other_stuff; end; endP1;

  17. Summary Monitors hold data to be protected from concurrent asynchrononous access Monitors can be used to manage shared resources of any type In C# lock( ) is preferred when enforcing mutual exclusion of shared data Semaphores require special hardware implementation (binary and counting) Test-and-Set is an uninteruptable instruction

More Related