The first read will take a moment for disk access, but successive reads after that should read from the same buffer because the system keeps a cache of blocks recently read from the disk. So, every n reads, working backward, there should be a pause for disk access, where n is the size of a block.
Doing this backwards should defeat optimization tricks that many systems incorporate to make sequential reads work faster. For example, on many systems, when block n of a file is being referenced, the system will automatically request blocks n+1 and n+2 in anticipation of their being needed.
Now, start reading backwards, one sector at a time, measuring how long each read takes. The delays should all be short and very similar to each other until you get back far enough that you hit a sector that was used long enough ago that it was ejected from the cache, so that you need to do disk I/O. That read and all following reads should take a longer time.
It is hard to do an experiment that distinguishes between RAM cache maintained by the operating system and RAM cache that is part of the disk controller itself.
On page 606, in the second to the last paragraph, it says that get request and put reply must be strictly paired. Two consecutive get request operations are forbidden. The only reasonable way to enforce this is to limit each thread to one RPC at a time, adding a state word to the status of each thread what request it is currently processing. If NIL, the thread is not processing a request. If non-NULL, the word points to the header buffer of the request currently being processed. Get request is only legal when this pointer is NULL, and it sets this pointer. Put reply is only legal if the header pointer matches this pointer, and it resets this pointer.
Part B The following alternate code has an appropriate population limit and conforms to the restriction inferred above:
fork N threads, each running the following code repeat wait( get request semaphore ) get request signal( get request semaphore ) process transaction put reply foreverHere, we used the get request semaphore to guarantee that only one thread at a time will wait for an incoming RPC. This may be unnecessary, but it doesn't hurt, and it gives exactly the same mutual exclusion as we had with a single thread doing all get-requests.