Synchronization: Semaphores

Similar documents
Shared Variables and Interference

Shared Variables and Interference

CS 162 Operating Systems and Systems Programming Professor: Anthony D. Joseph Spring Lecture 8: Semaphores, Monitors, & Condition Variables

Concept of a process

Semaphores INF4140. Lecture 3. 0 Book: Andrews - ch.04 ( ) INF4140 ( ) Semaphores Lecture 3 1 / 34

CS370 Operating Systems

Chapter 6: Process Synchronization

Models of concurrency & synchronization algorithms

CSE Traditional Operating Systems deal with typical system software designed to be:

Chapters 5 and 6 Concurrency

Page 1. Goals for Today" Atomic Read-Modify-Write instructions" Examples of Read-Modify-Write "

Concurrent Computing

G52CON: Concepts of Concurrency

Midterm on next week Tuesday May 4. CS 361 Concurrent programming Drexel University Fall 2004 Lecture 9

Last Class: Synchronization

Dr. D. M. Akbar Hussain DE5 Department of Electronic Systems

CSE 120. Fall Lecture 6: Semaphores. Keith Marzullo

Concurrency: a crash course

Background. The Critical-Section Problem Synchronisation Hardware Inefficient Spinning Semaphores Semaphore Examples Scheduling.

2.c Concurrency Mutual exclusion & synchronization mutexes. Unbounded buffer, 1 producer, N consumers

Page 1. Goals for Today" Atomic Read-Modify-Write instructions" Examples of Read-Modify-Write "

CS Operating Systems

CS Operating Systems

Deadlock and Monitors. CS439: Principles of Computer Systems February 7, 2018

Page 1. Goals for Today. Atomic Read-Modify-Write instructions. Examples of Read-Modify-Write

Synchronization: semaphores and some more stuff. Operating Systems, Spring 2018, I. Dinur, D. Hendler and R. Iakobashvili

Concurrent Processes Rab Nawaz Jadoon

CS-537: Midterm Exam (Spring 2001)

Process/Thread Synchronization

CMSC421: Principles of Operating Systems

Process Synchronization

Interrupts on the 6812

Operating Systems. Designed and Presented by Dr. Ayman Elshenawy Elsefy

CS 153 Design of Operating Systems Winter 2016

Semaphores. Mutual Exclusion. Inference Rules. Fairness: V may release a waiting process. Weakly fair, Strongly fair, or FIFO

CS3502 OPERATING SYSTEMS

Synchronization. CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han

CS420: Operating Systems. Process Synchronization

Programming Languages

Silberschatz and Galvin Chapter 6

Last Class: Synchronization. Review. Semaphores. Today: Semaphores. MLFQ CPU scheduler. What is test & set?

Concurrency. On multiprocessors, several threads can execute simultaneously, one on each processor.

SWEN-220 Mathematical Models of Software. Process Synchronization Critical Section & Semaphores

COMP 3430 Robert Guderian

Semaphores. Jinkyu Jeong Computer Systems Laboratory Sungkyunkwan University

What's wrong with Semaphores?

Process Synchronization

Lecture Topics. Announcements. Today: Concurrency (Stallings, chapter , 5.7) Next: Exam #1. Self-Study Exercise #5. Project #3 (due 9/28)

Spring 2018 PhD Qualifying Exam in Languages

CS 167 Final Exam Solutions

Condition Variables CS 241. Prof. Brighten Godfrey. March 16, University of Illinois

T Reactive Systems: Kripke Structures and Automata

Process Synchronisation (contd.) Operating Systems. Autumn CS4023

Forward Assignment; Strongest Postconditions

Reminder from last time

Multitasking / Multithreading system Supports multiple tasks

Introduction to Operating Systems

Synchronization problems with semaphores

SYNCHRONIZATION M O D E R N O P E R A T I N G S Y S T E M S R E A D 2. 3 E X C E P T A N D S P R I N G 2018

Chapter 8. Basic Synchronization Principles

Synchronization. CS 475, Spring 2018 Concurrent & Distributed Systems

OS Process Synchronization!

Operating Systems. Lecture 4 - Concurrency and Synchronization. Master of Computer Science PUF - Hồ Chí Minh 2016/2017

Chapter 5: Process Synchronization. Operating System Concepts 9 th Edition

Chapter 5 Concurrency: Mutual Exclusion. and. Synchronization. Operating Systems: Internals. and. Design Principles

CS370 Operating Systems

G52CON: Concepts of Concurrency

Chapter 6: Synchronization. Chapter 6: Synchronization. 6.1 Background. Part Three - Process Coordination. Consumer. Producer. 6.

Concurrency: Mutual Exclusion and Synchronization

Synchronization for Concurrent Tasks

Chapter 6: Process Synchronization

Semaphores. May 10, Mutual exclusion with shared variables is difficult (e.g. Dekker s solution).

Lecture 8: September 30

Resource management. Real-Time Systems. Resource management. Resource management

Deadlock and Monitors. CS439: Principles of Computer Systems September 24, 2018

Chapter 5 Concurrency: Mutual Exclusion and Synchronization

IT 540 Operating Systems ECE519 Advanced Operating Systems

Process/Thread Synchronization

The mutual-exclusion problem involves making certain that two things don t happen at once. A non-computer example arose in the fighter aircraft of

Concurrency. On multiprocessors, several threads can execute simultaneously, one on each processor.

Recap: Thread. What is it? What does it need (thread private)? What for? How to implement? Independent flow of control. Stack

Real-Time Systems. Lecture #4. Professor Jan Jonsson. Department of Computer Science and Engineering Chalmers University of Technology

Chapter 5: Process Synchronization. Operating System Concepts Essentials 2 nd Edition

Midterm Exam. October 20th, Thursday NSC

Concurrency. Lecture 14: Concurrency & exceptions. Why concurrent subprograms? Processes and threads. Design Issues for Concurrency.

Pre- and post- CS protocols. CS 361 Concurrent programming Drexel University Fall 2004 Lecture 7. Other requirements for a mutual exclusion algorithm

CS 333 Introduction to Operating Systems. Class 4 Concurrent Programming and Synchronization Primitives

Process Synchronization

Introduction to Operating Systems Prof. Chester Rebeiro Department of Computer Science and Engineering Indian Institute of Technology, Madras

ECE 462 Object-Oriented Programming using C++ and Java. Scheduling and Critical Section

Dealing with Issues for Interprocess Communication

MULTITHREADING AND SYNCHRONIZATION. CS124 Operating Systems Fall , Lecture 10

Thread Synchronization: Too Much Milk

Types, Expressions, and States

Background. Old Producer Process Code. Improving the Bounded Buffer. Old Consumer Process Code

Achieving Synchronization or How to Build a Semaphore

Synchronization. Race Condition. The Critical-Section Problem Solution. The Synchronization Problem. Typical Process P i. Peterson s Solution

CS370 Operating Systems

CSC501 Operating Systems Principles. Process Synchronization

CS4411 Intro. to Operating Systems Exam 1 Fall points 10 pages

Transcription:

Illinois Institute of Technology Lecture 26 4/25 solved Synchronization: Semaphores CS 536: Science of Programming, Spring 2018 A. Why Avoiding interference, while good, isn t the same as coordinating desirable activities. It s common for one thread to wait for another thread to reach a desired state. B. Objectives At the end of this lecture you should know The semantics of binary semaphores and their P and V operations. How to implement binary semaphores using await statements. How to solve the mutual exclusion problem using binary semaphores. C. Binary Semaphores and the Mutual Exclusion Problem One use for await statements is for solving the mutual exclusion ( mutex ) problem where we want to ensure that only one process at a time is in some critical section of code (e.g., writing to a shared database). Say thread S₁ contains a section of code CS₁ ( Critical Section₁ ) and thread S₂ contains CS₂, so our program includes [ CS₁ CS₂ ]. In the mutual exclusion problem, we want to ban interleaving of critical section code: Only one of the CS i should be executing at any given time. Making the CS i atomic solves the problem automatically, but if the execution of CS i is going to take time (e.g., because it involves I/O), we might want to interleave critical code with noncritical code. E.g., if thread 1 is in CS₁ because it's writing to the database, it's fine for thread 2 to be doing some calculations in its noncritical code. We don't want both threads to be writing to the database simultaneously, so thread 1 being in CS₁ should prevent thread 2 from being in CS₂. The traditional solution to mutex problem uses binary semaphores. A binary semaphore is a boolean flag (initially T) with blocking properties: Semaphore = true indicates permission to continue. Semaphore = false indicates lack of permission. Operations on a binary semaphore s: Init(s, b): Initialize s to b (T or F). P(s): Get permission to continue (and deny it to everyone else). If s is true, we set it to false and continue. (The test and set are done atomically.) If s is false, we wait until it becomes true; then we set it to false and continue. V(s) means Give up permission (so someone else can get permission). If s is false, we set it to true, select one of the P(s) calls that are waiting and let that call continue. If s is true, leave it true. CS 536-05: Science of Programming 1 James Sasaki, 2018

Different implementations of semaphores can differ on how to select one of the waiting P(s) calls. The original scheme selected nondeterministically. For fairness, we might actually keep a priority queue of waiting calls. Semaphores were invented by Edsgar Dijkstra The names P and V come from Dutch V stands for verhoog = increase. P stands for ( prolaag, which is short for probeer te verlagen, or try-and-decrease. In practice, people often use synonyms for P and V: Synonyms for P: wait, acquire, lower. Synonyms for V: signal, release, raise. Using semaphores, the mutual exclusion problem is solved as follows: Init(s, T); // s true iff it's ok to enter the critical section [ ; P(s); CS₁; V(s); // thread 1 and its critical section ; P(s); CS₂; V(s); ] // thread 2 and its critical section We can encode semaphores using await statements: Init(s, b) s := b P(s) await s then s := F end Atomicity of await ensures no one can change s between the time that we notice s is T and then set s to F. V(s) s := T For the mutual exclusion problem, Let the semaphore be mu ( mutex ) Let NC₁ and NC₂ be noncritical section code. We'll model repeated attempts to enter critical section code by putting the critical code in a loop. The auxiliary variables u₁ and u₂ ( using critical section ) are true when threads 1 and 2 respectively are in their critical sections. Init(mu,T); u₁ := F; u₂ := F; [ while B₁ do NC₁; P(mu); u₁ := T; CS₁; u₁ := F; V(mu) od while B₂ do NC₂; P(mu); u₂ := T; CS₂; u₂ := F; V(mu) od ] If we translate P and V using await, we get the following program S i for thread i (where i = 1, 2). Note we ve pulled the set of u i := T into the await body to make it atomic with the reset of mu. while B i do NC i ; od await mu then mu := F; u i := T end; CS i ; // Get permission < mu := T; u i := F > // Release permission CS 536-05: Science of Programming 2 James Sasaki, 2018

D. Sequential Correctness of the Mutex Program Below is a full sequential annotation of S i. The loop invariant includes a global invariant p₀ (u ₀ u ₁) (mu u ₀ u ₁)) that is maintained across all threads. In addition, there s a local part to the loop invariant, u i, which means "we're not in a critical section". Since we're running the loop forever, the thread postcondition could have been false, but making it the global invariant seems more reasonable. Below, let j be the index used in S i to name the other thread. (Sets {i, j} and {1, 2} are equal) {inv u i p₀} // where p₀ (u i u j ) (mu u i u j ) while B i do {u i p₀} NC i {u i p₀}; await mu then mu := F; u i := T end; {m u u i p₀} CS i ; {m u u i p₀} {u j } { F ( F u j ) (T F u j )} < mu := T; u i := F > {u i (u i u j ) (mu u i u j )} {u i p₀} // add mu to invariant? [4/25] od {u i p₀ B i } // We're in our CS // from u i p₀ in line above // wp of atomic assignments // expanding p₀ Here's a standard annotation of S i : {u i p₀} // where p₀ (u i u j ) (mu u i u j ) while B i do {u i p₀ B i } NC i ; od {u i p₀ B i } {u i p₀} await mu then mu := F; u i := T end; {m u u i p₀} CS i ; {m u u i p₀} < mu := T; u i := F > // P(mu) // V(mu) E. Interference Freedom of the Mutex Program Let's verify that thread S i doesn't interfere with the other thread, S j. (By symmetry, we'll find that S j doesn't interfere with S i ). The predicates we don't want to interfere with are: u j p₀ where p₀ (u i u j ) (mu u i u j ) m u u j p₀ (Let's assume that we don't interfere with the loop test B j so that the variants of u j p₀ that add B j and B j aren't relevant.) The code in S i that we have to check is {u i p₀ B i } NC i { } CS 536-05: Science of Programming 3 James Sasaki, 2018

{u i p₀} await mu then mu := F; u i := T end { } {m u u i p₀} CS i { } {m u u i p₀} < mu := T; u i := F > { } Only the P(mu) and V(mu) code actually need to be checked because NC i and CS i don't modify u j or mu, so they both maintain (u j p₀) and (m u u j p₀). So altogether we have four interference tests 1. {u i p₀} P(mu) { } with u j p₀ 2. {u i p₀} P(mu) { } with m u u j p₀ 3. {m u u i p₀} V(mu) { } with u j p₀ 4. {m u u i p₀} V(mu) { } with m u u j p₀ Test 1: {u i p₀} P(mu) doesn't interfere with u j p₀. Here's an annotation that shows interference freedom: {(u i p₀) (u j p₀)} // where p₀ (u i u j ) (mu u i u j ) await mu then end {(u i p₀) (u j p₀) mu} {u j (u j T) (F u j T)} mu := F; u i := T {u j (u j u i ) (mu u j u i )} {u j p₀} // precondition of await body // wp of postcondition // p₀ expanded Test 2: {u i p₀} P(mu) doesn't interfere with m u u j p₀. Note: {m u } await mu makes the contradiction m u mu the precondition of the await body; this lets us use anything for the postcondition of the await body. {(u i p₀) (m u u j p₀)} // where p₀ (u i u j ) (mu u i u j ) await mu then!!!!!!! // P(mu) in S i end; {m u u j p₀} {m u mu} {F} mu := F; u i := T {F}{m u u j p₀} Test 3: {m u u i p₀} V(mu) doesn't interfere with u j p₀. {(m u u i p₀) (u j p₀)} // where p₀ (u i u j ) (mu u i u j ) {u j (u j F) (T u j F)} < mu := T; u i := F > // V(mu) in S i {u j (u j u i ) (mu u j u i )} {u j p₀} // wp of the atomic assignments // p₀ expanded CS 536-05: Science of Programming 4 James Sasaki, 2018

Test 4: {m u u i p₀} V(mu) doesn't interfere with m u u j p₀. Again, we find a contradiction: We assume u i u j hold when p₀ implies u j u i. {(m u u i p₀) (m u u j p₀)} // where p₀ (u i u j ) (mu u i u j ) {(m u u i u j ((u j u i )...)} {F} V(mu) {F} {m u u j p₀} // Expanding p₀ and rearranging // Contradiction // false implies anything F. Deadlock Freedom of the Mutex Program For deadlock freedom, we need to look at the potential deadlock conditions. For thread i, we have an await mu statement with precondition (u i p₀) and the thread s postcondition (u i p₀ B i ). (Recall p₀ (u ₀ u ₁) (mu u ₀ u ₁).) Let D₁ = {(u ₁ p₀ m u ), (u ₁ p₀ B i )} (await precondition test), (thread postcondition) Let D₂ = {(u ₂ p₀ m u ), (u ₂ p₀ B i )} The set D of deadlock conditions is { (u ₁ p₀ m u ) (u ₂ p₀ m u ) // Both threads blocked (u ₁ p₀ m u ) (u ₂ p₀ B j ) (u ₁ p₀ B i )) (u ₂ p₀ m u ) } // # 1 blocked, # 2 done // # 1 done, # 2 blocked The program is deadlock-free because all three of the deadlock conditions are contradictions: They each include u ₁ and u ₂ (so we must have mu), but we also have m u. So we can apply the rule for Parallelism with Deadlock Freedom and get our mutex program {T} mu := T; {mu} u₁ := F; u₂ := F; {mu u ₁ u ₂ p₀} {(u ₁ p₀) (u ₂ p₀)} [S₁ S₂] { } G. Counting Semaphores Boolean semaphores are good for situations with two states; for situations with many states, it's useful to have counting semaphores, which have natural number values. Init(s, n) initializes the semaphore to n (for natural number n 0). P(s) await s > 0 then s := s-1 end The P operation waits if decrementing the semaphore would make it negative. V(s) s := s+1 A boolean semaphore is equivalent to a counting semaphore where n 1. Recall the Producer/Consumer Problem: The producer adds items to a finite buffer (but needs to wait if it can't add anything to the buffer); the consumer removes items from the buffer (but needs to wait if the buffer contains nothing to consume). We can solve the Producer/Consumer Problem with two counting semaphore(s): CS 536-05: Science of Programming 5 James Sasaki, 2018

The nbr_unused semaphore will track the number of empty slots in the buffer (initially, the buffer capacity). The producer does a P on this semaphore before it adds an item to the buffer; the consumer does a V on it when it removes an item from the buffer. The nbr_used semaphore will track the number of used slots in the buffer (initially, zero). The consumer does a P on this semaphore before it removes an item from the buffer; the producer does a V on this semaphore when it stores an item into the buffer. The top-level code is: InitializeBuffer(b, N); Init(nbr_unused, N); Init(nbr_used, 0); [Producer Consumer] The producer is while done do # thing_p := Create(); # P(nbr_unused); BufferAdd(b, thing_p); # V(nbr_used); od The consumer is: while done do # P(nbr_used); # thing_c := BufferRemove(b); V(nbr_unused); # Consume(thing_c) od There's a critical section problem that comes up with the buffer operations: We almost certainly don't want buffer add and remove operations interleaving because that might leave the buffer in an inconsistent state, so the buffer operations are critical sections. If we have multiple producer or consumer threads running, then making the buffer operations critical sections also keeps (e.g.) two buffer adds interleaving. CS 536-05: Science of Programming 6 James Sasaki, 2018

Synchronization: Semaphores CS 536: Science of Programming A. Why It s common for one thread to wait for another thread to reach a desired state. B. Objectives At the end of this activity assignment you should be able to State the semantics of binary semaphores and their P and V operations. Implement binary semaphores using await statements. Solve the mutual exclusion problem using binary semaphores. C. Problems For the upcoming exam, it s sufficient to know the answers to the following questions. 1. For binary semaphores a. What is a (binary) semaphore? b. How can we implement P(s)? What does P(s) do? c. How can we implement V(s)? What does V(s) do? 2. Repeat the previous problem, but for counting semaphores. 3. How can we simulate a boolean semaphore using a counting semaphore? 4. How do we decide what to initialize a counting semaphore to? A binary semaphore? 5. How do we solve the critical section problem using a binary semaphore? When does it cause waiting? How is the semaphore initialized? 6. In the solution to the producer-consumer problem, what did our two counting semaphores count? How do we initialize them and use them? When do the producer and consumer wait, and for what? When are a waiting producer or consumer woken, and why? CS 536-05: Science of Programming 7 James Sasaki, 2018

Illinois Institute of Technology Lecture 26 Activity 26 Solution: Synchronization: Semaphores 1. (Binary semaphore) a. A binary semaphore is a permission flag. If the flag is true, we have permission to do some action associated with the semaphore. b. P(s) await s then s := F end; The P(s) operation waits until s is true, then sets s to false. c. V(s) s := T. The V(s) operation sets semaphore s to true. If one or more threads are waiting for their P(s) operation to complete, then one of them gets to continue. 2. (Counting semaphore) a. A counting semaphore s holds an integer 0; the value is taken as a number of available resources. b. P(s) await s > 0 then s := s-1 end. The P(s) operation waits until s > 0 then it decrements s. I.e., it models waiting until there exists at least one resource and then taking it. c. V(s): s := s +1. It models returning a resource and making it available. If this sets s to 1, then one of the waiting P(s) operation gets to continue. 3. We can simulate a boolean semaphore as a counting semaphore that has a maximum value of 1. 4. Viewing a counting semaphore as modeling the number of available resources, we should initialize it to the number of available resources at the point of initialization. A binary semaphore can be viewed as modeling having 0 or 1 permissions to do something, so we initialize it to F or T depending on whether permission exists initially or not. 5. To solve the critical section problem using a binary semaphore s, we surround each critical section with P(s) and V(s and initialize s to T. This ensures that only one thread ever gets permissions to enter its critical section. 6. To solve the producer-consumer problem One semaphore holds number of used buffer slots; the other holds the number of empty buffer slots. They get initialized to 0 and size of buffer respectively. The consumer does a P on the number of used buffer slots, so it waits if the buffer is empty. The producer does a P on the number of empty buffer slots, so it waits if the buffer is full. When the consumer removes something from the buffer, it does a V on the number of empty buffer slots (which may then awaken a waiting producer). When the producer adds something to the buffer, it does a V on the number of used buffer slots (which may awaken a waiting consumer). CS 536: Science of Programming 8 James Sasaki, 2018