The solution that only allows a philosopher to pick up the chopsticks when they are both available (solution #5 in the lecture notes, and all the later solutions) prevents "Hold and Wait" from occurring.
The solution that has even philosophers pick up the chopsticks in one order, and odd philosopher pick them up in a different order (solution #4 in the lecture notes) prevents circular waiting.
Some of you tried to say that a solution broke Mutual Exclusion. The only way to do that would be if philosophers could simultaneously pick up the same chopstick, which goes against the definition.
You can break the "no preemption" if you make it so that a philosopher who holds a stick and is waiting for another may be signaled to drop his or her stick. I gave credit for that answer if you defined it precisely (e.g. "no preemption can be broken if you make a philosopher drop his chopstick" is not precise enough. Is he eating? That would be a problem).
This question was an easy one.
The inode is a nice file allocation scheme because it handles small and large files efficiently. The small files benefit from the direct block pointers -- there is no external or internal fragmentation, and the direct pointers avoid extra disk lookups (as are required when indirect pointers are used, or when a FAT is used). As the file size grows, the single indirect block allows for flexibility -- for example performing random-access I/O only requires two disk operations, with no external fragmentation and very little internal fragmentation.
The double and triple indirect blocks allow the file to grow to colossal sizes with little fragmentation and relatively little extra I/O.
With RAID-4, there is a dedicated disk drive P that contains the bitwise parity of the other drives. Let's name the data drives D1 ... Dk. Then the first byte of drive P is the bitwize exclusive-or of the first bytes of drives D1 through Dk.
If any disk drive fails, we may recover its contents as the bitwise parity of the surviving drives. Parity is beautiful.
With RAID-5, you simply rotate the identity of the drives at regular intervals. That alleviates hot spots on the disk.
RAID arrays are motivated by the need to provide large-scale storage out of small storage components. It's cheaper to do that than it is to build big disks. It also provides faster storage because it is quicker to write k blocks to k drives in parallel than it is to write them to one drive. Of course, when you add components, you increase the likelihood for failure; hence why we need the P drive.
RAID drives do a good job of writing multiple blocks, because it requires just the extra calculation (which is fast) and the extra I/O to the P disk. Writing single blocks is more expensive, because to do so, you need to read the old value of the data and the parity, subtract the old data and add the new data, and then rewrite the parity. We hope that good caching in the RAID controller mitigates this.
Finally, the killer of RAID-4 and RAID-5 is the latent sector failure. This is when a sector fails, due to a head crash or a failed write, and it is not detected at the time. Then, if another drive fails, we cannot reconstruct the data. This is the motivating scenario for RAID-6.
![]() |
LRU: When you need to fault in a page, you evict the page that you accessed the furthest in the past. The answer is b.
![]() |
FIFO: pretty obvious. The answer is e.
![]() |
Clock: Now we make use of the "reference" bit and a pointer that treats the frame pool as a circular buffer. When we need a new frame, we start with the pointer and cycle through the buffer until we find a page with an unused reference bit. That is the page that we replace. As we cycle through, we clear the set reference bits. This is depicted below. The answer is f.
![]() |
![]() |
Now, a lot of you got confused and said that the page had to occupy 11 bits (since there are 2048 pages), and then you didn't know what to do with those six extra bits. You got creative, and many of you gave reasonable responses after that. I gave some points to that. However, remember, a virtual address does not have to have a physical page associated with it, so we can use more than 11 bits to represent the page. For example, I could have set the first 2048 PTE's to be invalid. Then page 0x800 (the 2049-th) page could have a valid PTE, and address 0x20000 would be valid -- that's page 2048, offset 0. This is an important point.
Again, many of you said "Page 217-1 is bigger than 211-1 so the address can't exist." That's not the issue, and although it will trouble you, it received no credit. The issue is that your page table has to occupy consecutive physical memory addresses, and since the page table itself is greater than 128K, it cannot be held.
You got 0.3 points if your physical address was wrong but the last hex digit was correct.
The answer: "Shaft!" --- damn right. (Written and performed by Isaac Hayes). If you don't know it, spend a buck on Itunes or Amazon and get it. It's a classic (the intro music to the movie "Shaft" -- the original with Richard Roundtree, not the remake with Samuel L. Jackson).