Dining savages


The problem of the dining savages (an allusion to the classic dining philosophers) is based on the arguably tasteless analogy of a number of members of a primitive culture, hereinafter called the "savages", sharing a meal from a single pot. The primary abstractions are the savages themselves, a cook, and the pot. The pot contains a certain number of servings of savage sustenance (the nature of which will be left to your imagination). Each of the savages can freely remove a serving from the pot so long as the pot is not empty. So before taking a serving, a savage must check to make sure the pot is not empty. In the case in which the pot is empty, the savage must wake up the cook to refill the pot, after which the feast continue. The savages, then, can eat only when the pot is not empty, and the cook can fill the pot only when the pot is empty.


The primary shared resource here is the pot, represented by class POT, which is accessed for different purposes by both the savages and by the cook. POT has queries is_empty and is_full that can be used by savages (modeled by class SAVAGE) and the cook (class COOK). POT also has a feature to allow refilling of the pot. This feature is exported only to COOK. Another feature, this one exported only to SAVAGE allows the removal of a serving from the pot.

The cook can also be viewed as a resource shared among all the savages. Whenever a savage executes the feature that checks the pot, he must have exclusive access to both the pot and the cook. If the pot is empty then the savage uses his access to the cook to request a refill. If the pot is not empty, then the savage exits the routine, and goes on to execute the routine that removes a serving from the pot.

In the root class, you can adjust the number of savages, the size (in servings) of the pot, and how hungry the savages are. The hunger index indicates how many times a savage will take a serving from the pot and eat it before becoming sated. So if the pot holds 20 servings and there are 5 savages with hunger index of 4, then the pot will become empty just as the last savage takes his last serving, meaning that the pot will not require refilling. In the same scenario, if the hunger index were 10, then 50 servings total would be required, resulting in the need for the cook to be notified to refill the pot 2 times ... and 10 servings leftover ... presumably for tomorrow's breakfast.

The root class creates the pot, then the cook, then some number of savages. As the savages are created, their lives are launched. To occupy themselves, they repeatedly check the pot, take a serving, and eat. They give this all up once they have eaten the number of servings prescribed by their hunger index. During the check of the pot, if the pot is empty, a separate call is made to the cook requesting that the pot be refilled, and the savage goes on about the business of removing a serving from the pot. It is possible that when the savage then tries to get a serving from the pot, the pot will still be empty. In this case the precondition on get_serving_from_pot will cause the savage to wait until such time as the pot is no longer empty.

Whenever the cook is requested to refill the pot, the {COOK}.cook procedure is called. The procedure takes as an argument the pot which is declared of course as separate. So access to the pot must be guaranteed before cook can execute. The cook procedure has a precondition that causes it to wait if the pot is not currently empty.