A number of racers will compete in a race with three obstacles: The Forest, The Mountain and The River. Before the first obstacle and between any two obstacles, the racers will stop for rest and food (by sleeping for a random time). The sequence of events will be something similar to:
Rest
Forest
Rest
Mountain
Rest
River
Get Home
Note: you will need to keep track of the time when a racer started a specific obstacle and when it ended that obstacle, together with the time when the racer started the race until he finished the race.
The obstacles are described below:
The Forest:
The racer using a compass will have to find in the forest a map that contains a magic word. The forest will be a file of more than 300 but less than 500 randomly generated words of 4 letters chosen from the set {a, b, c, d}. The length of the magic word will also be 4 letters long, containing letters from the same set {a, b, c, d}. If the map with the magic word is found, the racer can leave the forest right away.
The Mountain:
The racers have to pass a very narrow passage. Only one racer can be on the passage at a given time. Using semaphore(s) implement mutual exclusion over passing the narrow passage.
The River:
Only numLines racers can cross the river at a given time. The racers will form groups of size numLines (use semaphore(s)) to block the racers in the group). Once the group is formed, the judge is signaled that they are ready. If all numLines are available (use semaphore), the judge will let group of racers move on.
Once a racer crossed the river he will wait (use semaphore(s)) for the reports. The judge will announces the times after all the racers are done with their obstacles. Once the reports are given the judge will let know the last racer ((use semaphore(s) ) that is time to go home, and next he will wait (use semaphore) for all the racers to leave. Each racer knows the next racer in the sequence. For example, racer1 knows racer2, racer2 knows racer3 and so on. For example racer 9 will wait for racer 10 to leave and will signal racer 8 that he is leaving. Consider that the last created racer will just go home immediately, and that the first racer before leaving will let the judge know that everybody left.
Judge:
The judge is responsible with presenting the order in which racers ended the race. There will be two reports:
1. First report will consider the time it took for each racer to end the entire race. (Including the resting time)
2. The second report will consider the times that it took for each racer to pass each of the obstacles. (Excluding the resting time)
Using Java programming, synchronize the threads, in the context of the problem. Closely follow the implementation requirements. The synchronization should be implemented through Java semaphores and operations on semaphores (acquire and release)
For Mutual Exclusion implementation use Mutex semaphores, no volatile variables.
For semaphore constructors, use ONLY: Semaphore(int permits) Creates a Semaphore with the given number of permits and nonfair fairness setting.
As methods use ONLY: acquire(), release(); You can also use:
getQueueLength()
Returns an estimate of the number of threads waiting to acquire.
hasQueuedThreads()
Queries whether any threads are waiting to acquire.
DO NOT USE ANY OF THE OTHER METHODS of the semaphore's class, besides the ones mentioned above.
Any wait must be implemented using P(semaphores) (acquire), any shared variable must be protected by a mutex semaphore such that Mutual Exclusion is implemented.
Document your project and explain the purpose and the initialization of each semaphore.
DO NOT use synchronized methods (beside the operations on semaphores).
Do NOT use wait( ), notify( ) or notifyAll( ) as monitor methods. Whenever a synchronization issue can be resolved use semaphores and not a different type of implementation.
You should keep the concurrency of the threads as high as possible, however the access to shared structures has to be done in a Mutual Exclusive fashion, using a mutex semaphore.
Many of the activities can be simulated using the sleep(of a random time) method.
Use appropriate System.out.println( ) statements to reflect the time of each particular action done by a specific thread. This is necessary for us to observe how the synchronization is working.
You must write a pseudo-code (not a java programming code, not a java-pseudocode ). The pseudo-code must be heavily documented. You must mention the use of each semaphore, mention its type and initialization. The used semaphores follow the definitions given in class and lecture notes. The semaphores' queues use a First Come First Serve policy.
Keep in mind, you have to implement two execution codes, one for each type of thread.