Lecture 2, unit 1: Introduction to Semaphores

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi welcome to the second set of lectures on concurrency in CSI 37 operating systems for the spring of 2013 our topic today is semaphores what you should learn is the difference between these synchronization capabilities provided by locks and what semaphores can do and second to identify the appropriate use of semaphores as compared to locks user code restoring problems and third to learn about their basic operations and how to initialize them so let's first look at the motivation for some of course why do we need some of course if we have these things like locks that would seem to work so well the problem is that locks only provide one kind of operation which is mutual exclusion they make sure that only one thread executes it's holding the lock at a time for example a lock protecting a critical section this is very useful for things like making sure your bank balance gets updated but doesn't solve all the problems we might want to solve for example another thing we really want to do is to place an ordering on how threads get scheduled meaning we want some code in one thread to be guaranteed to run before thread another code a standard example this is the producer-consumer problem we've talked about many times this semester in this example of producer creates a resource or some kind of data and the consumer then consumes that resource simple example this is pipelines on the UNIX command line suppose if the pipeline show with the PS command the grep command at the WC command in this case the PS command produces output and the grep command needs to wait for PS to produce it before it can consume it out but similarly the WC command has to wait for grep to produce output before canned run so here we have an ordering problem where we need one program to run after the program typically in this problem we don't want producers to consumers and consumers to run in lockstep for example we don't want it say let PS run for one line about but then run grep for one line about but then WC for one line M output because this causes a lot of context switching it is therefore inefficient instead we'd like to put a fixed size buffer between the producer and the consumer this allows the producer to run as long as the buffer is in full it can keep on adding data the consumer can run pulling data out of the buffer as long as it is isn't empty this means that we now have a new kind of ordering problem where we do we still need to have threads that consider wait for each other to run the producer waits at the buffers full and the consumer waits at the buffer is empty so what's up now at what time of cars are and then we'll learn how they consult this problem so a semaphore is really a higher-level synchronization primitive in lakhs it's often built using locks and was invented by Edgar Dijkstra around 1965 as part of the taa operating systems project a semaphore internally is a counter that has some special operations on it a signal operation and a weight operation let's start with weight first on the weight operation the counter is decremented if the counter is zero then the weight operation will block until another thread signals the semaphore so this is says this is how you wait for things to happen is by calling weight on a semaphore this is also called P original in the original version which is for the Dutch word for test because Dijkstra lived in the Netherlands and it's also called down in some implementations the second operation in semaphore is signal which increments the counter and if any threads are waiting it wakes one up this is also called Vee after the Dutch word for increment and also called up the third operation is the initialization function something likes eminent which takes out semaphore and sets the initial counter value we'll see it later on why this is an important thing to be able to do so let's look now at the implementation this is pseudocode for the algorithm inside of a semaphore it's not actually the real code for a semaphore though so first of all we have to have a structure that has a value which is what gets counted up and down and then it needs a cue for the list of processes because we need to keep track of which processes are waiting so they can be woken up later the weight function is exactly what I said if the value of the semaphore is greater than zero it decrements the value and returns otherwise it adds the process to the list and blocks until somebody wakes it up the signal function checks to see if the list is empty if it's not empty then signal will remove a process from the list and wake it up otherwise it increments the value one thing to note is both the weight and the signal operations are critical sections because they access shared state the X is the X is the value and axis the Q therefore these have to be executed atomically with respect to each other and are usually implemented using spin locks semaphore is our block operations they're blocking because threads that are that are waiting for semaphore aren't spinning like the locks that we saw before but they're blocking they wait on a cue instead releasing the CPU for another thread or process to use so when weight is called by a thread if the semaphore is available which means the count is 1 or greater the value is 1 or greater at the thread continues the semaphore is unavailable then the thread blocks weights in the queue and gives the CPU up to another thread or process calling signal sort of opens the semaphore if a thread is waiting in the queue then exactly one thread is unblocked and it's put on the ready queue and can start running whenever these scheduler says it can run if no threads are in the queue then the signal is remembered for the next time a wait is called this is done by incrementing the value this means if there's a signal and there's no spread waiting the next thread that calls wait may be able to run without weight without having to block first because that signal is remembered so let's look now at how to initialize semaphores so as we said you can initialize a different values and I'd like that we'll talk about what those different values mean so suppose we initialize the semaphore to one what does that mean well the first thread that calls weight will go right through without waiting and the semaphore value will go from 1 to 0 if a second thread calls weight though it will block because the value is 1 the semaphore value stays at 0 when the thread goes on the queue if the first thread then calls signal the semaphore value stays at zero byte it wakes up the second thread and the second thread returns from weight if the second thread now call signal remember the value was 0 the value will now go from 0 to 1 this means that the next part of weight will not wait because the value is 1 this may look like a very familiar pattern of synchronization that we've seen before and the fact is that it's basically a mutex lock if you initialize a semaphore value to 1 and every thread has a set of paired calls to weight followed by a value to signal then a semaphore X just like a lock this is useful because if you need locks in your system a semaphore is one way to do it so what happens if we initialize a semaphore value to 2 here's the code for semaphores to remind you what they do so if we call Semin it some comma 2 what happens when multiple threads now call weight well when the first weight calls way some upper value will go from two to one but the thread will continue when the second thread calls wait the value will go from one to zero and it will continue to it's only when the third thread calls wait that the semaphore value stays at zero and the third thread blocks what this means is that if you initialize the semaphore to some value greater than zero this indicates how many threads can call weight without actually waiting or you can think about this as the number of threads that can hold the semaphore at once in this case we had two threads that could sort of hold the semaphore at once so in general the use of having a semaphore value is for allocating a number of resources suppose for example we have a number of shared buffers the different threads can use every time a thread allocates a shared buffer it can call weight to wait until shared buffers available this will decrement the count of available shared buffers stored by the semaphore when a thread calls signal it'll indicate a shared buffers available and one of the threads that's waiting can wake up and use it this also may be useful in a system that has multiple devices that can be used by one thread at a time this is the end of unit 1 on semaphores please take the first quiz on semaphores before watching the next lecture
Info
Channel: Mike Swift
Views: 160,871
Rating: 4.7912621 out of 5
Keywords:
Id: KZU4ANBoLTY
Channel Id: undefined
Length: 7min 50sec (470 seconds)
Published: Tue Apr 16 2013
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.