CSE 451 4/21/2003
Note taker: Christophe Bisciglia
What was the point of today’s lecture?
To understand why the hardware must support an atomic read, modify, write (ARMW) instruction if the OS is to support concurrent threads of execution.
There are three hard, and one soft requirement of any synchronization scheme.
1.) Mutual Exclusion (mutex) – this simply means that there will be at most one thread in any given critical section.
2.) Progress – If the critical section (CS) is empty, a thread can get in.
3.) No Starvation – If a thread wants in, it will eventually get in. There was some confusion about this in lecture, but after all was said, it boils down to no thread not in the CS can keep another thread out of the CS.
4.) Efficient – This is the soft one, but it goes without saying that you must do 1-3 in such a way that isn’t so slow, nobody will use it.
So why to we need an ARMW to do this? Think of the simplest scheme to protect a critical section. There would be one bit gets flipped on when a thread is in the CS. In the following code, b is jsut such a bit - a shared resource that is on when a thread is in the CS, and off otherwise. The code may look something like this:
1: if(!b) 2: b = 1; 3: else 4: goto line 1; 5: //CS 6: b = 0;
So, this may appear to solve the problem, but remember that threads can be pulled off the processor by the "hand of God" (the scheduler) at any time – possibly the least convenient time for the developer. So, what will undoubtedly happen is, one thread will get to line one, and see that the CS is free, and then, before flipping b, another thread will get into the CS. Before the second thread gets through the CS, the scheduler could let the first thread back in, hence stomping all over the other.
So, how do we solve this problem? There’s 2 ways that have substantial downsides, and one that actually provides a useful building block for building synchronization schemes.
1.) Decker’s algorithm – nobody uses it, but if you’re bored, it’s in the book.
2.) Turning off interrupts – sure, it’ll work until you bring a second processor into the mix, but it also makes modifying the OS very difficult – do not do this...
3.) When software fails, let the people who make the hardware deal with it – what we need is an instruction that performs the ARMW – TestAndSet (TAS)
TAS(b) returns 1 if b was zero prior to the call, and hence now set to one. This allows for a correct entrance to a CS (that still has problems nonetheless).
1: while(!TAS(b));
The problem with this method is, although its correct, it creates what is called a spinlock. A spinlock is when the processor is 'spinning', and is thus prevented from getting any useful work done, instead of merely waiting for an event to happen. Despite its problems, the ARMW is the building block for successful synchronization schemes. This will all become clearer when the concept of yielding is brought into play.
Brian now proceeds to draw way to many lines with labels for CS and quantum (Q) – long story short, you want to size of your CS to be small with respect to the quantum (the time slice). The size of a CS should be small with respect to the quantum (the time slice), because this would reduce the likelihood of threads having to wait a long time.