operating systems

profileOrange@123
2020-Spring-CS554AH2-Project2-1.pdf

Prof. Pitts CS554AH2: Operating Systems Spring 2020

Programming Assignment 2 Project Delivery: You should submit three Java programs in a ZIP file through Canvas by the project due date. Do

not use packages in any of your programs submitted for this assignment.

Part 1: In the first program, you will add synchronization (using semaphores) to a program that reads and displays a file. However, the file is read by some number of threads as indicated by the programs command line arguments.

I provide a starter program for you to work from for this part of the assignment. The program uses command line arguments as so:

java FileThreads InputFile.txt <num-threads>

where InputFile.txt is the input file the threads read (it could be called anything, but I supply a file called InputFile.txt) and <num-threads> is the number of threads to start (must be less than 15). To run the program in Jgrasp with command line argument, go the the Build menu and click Run Arguments. This will open a textfield above the edit area in which you can type the command line arguments.

The main method verifies that the command line arguments exist and are valid (the file exists and can be opened, and the number of threads is less than or equal to 15). The main method then creates a private log (as a StringBuilder class object) for each thread, creates a runnable object (giving the private log and index as arguments to the constructor), and then starts the thread.

The run method is shown on the next page. The input file is a Java FileReader object, which supports the read() method. The read() returns an integer value that either represents the character read from the file, or is -1 to represent the end of the file. The read() method also can throw an IOException, which is caught. After the call to the read() method, Thread.sleep() is called to put in a random delay. Since the Thread.sleep() can throw an Interrupted Exception, this is also caught. Note that in any of the situations for end the thread’s reading of the file (end of file, IOException, or InterruptedException), the behavior is the same: make all threads stop.

After the Thread.sleep() method returns, the character that was read is added to the end of the main log (in the variable mainLog) and to the end of the thread private log (in the variable myLog).

When this program is run as is (unless you run it with only one thread), you’ll note that the display of the main log is nothing like the original file. In fact, you may find that the program occasionally throws an ArrayOutOfBoundsException on the append to one of the logs. Your task for this part of the assignment is to identify the critical section of the run method, define and initialize a binary semaphore, and use the semaphore acquire() and release() methods to protect the critical section. Remember, when a thread acquires the semaphore, it must eventually release it for correct behavior, no matter what path through the code is taken.

1/4

Prof. Pitts CS554AH2: Operating Systems Spring 2020

Part 2: The next part requires you to add a set of counting semaphores to the provided Java program to solve the Tea Drinkers Problem. The program again requires command line arguments and is called as

java TeaParty <num-threads>

where <num-threads> is the number of threads to start. In the description of the problem that follows, n is the number of threads.

The Tea Drinkers Problem: A group of n tea drinkers sit around a table to drink tea and talk. To drink tea, each tea drinker requires a cup, a saucer, and a spoon and tea drinker cannot drink tea until the tea drinker has all three. There are only n-1 cups, n-1 saucers, and n-1 spoons but any tea drinker can take any cup, saucer, or spoon as long as it is free. Each tea drinker is represented by a runnable class with the run method shown on the next page.

2/4

1. public void run() { 2. // use to generate a sleep between readng from the input file 3. // and writing the character read 4. Random r = new Random(System.nanoTime()); 5. // this loop holds the worker threads until the main thread has started 6. // them all 7. while(! keepgoing) /* Empty statement */ ; 8. // a count for the display statement each thread prints 9. // if the count display stops without the final results, there 10. // may be a problem in your semaphore code. 11. int count = 1; 12. // main loop 13. while(keepgoing) { 14. System.out.println("Thread " + me + " read " + count++); // count display 15. int c; // to read the next character 16. try { 17. if((c = inputFile.read()) < 0) { // if read() returns -1 18. // thenend of file 19. keepgoing = false; // stop the threads 20. System.out.println("Thread " + me + " is finished<*>"); 21. return; 22. } 23. Thread.sleep((r.nextInt(5)+1)*10); // sleep 24. } catch(IOException ie) { // read can throw this 25. System.out.println("Caught IOException in thread " + me); 26. keepgoing = false; 27. return; 28. } catch(InterruptedException iex) { // sleep can throw this 29. System.out.println("Caught InterruptedException from sleep()"); 30. keepgoing = false; 31. return; 32. } 33. mainLog.append((char) c); // add character to main log 34. myLog.append((char) c); // add character to private log 35. } 36. System.out.println("Thread " + me + " is finished<*>"); 37. }

Prof. Pitts CS554AH2: Operating Systems Spring 2020

You will use this class as an inner class of a public class called TeaParty. This class will also define a set of semaphores that are used to synchonize the tea drinker threads in their use of the cups, saucers, and spoons. The main method of TeaParty will initialize the semaphore counts (you will use counting semaphores, one for each of the three items the tea drinkers need) and then the main method will create and start n TeaDrinker threads (you main method should get the value for n from the String array parameter of the main method.

Add code in the highlighted area to use the semaphores to synchronize the tea drinkers to use the n-1 sets of cup, saucers, and spoons.

Submit your Java program TeaParty.java for this part of the project as part of your zip archive file.

The Java Semaphore class is defined in the java.util.concurrent package. The semaphore methods that you will need to use are:

• Semaphore(int permits), the constructor. permits is the intial value for the semaphore count.

• void acquire() Acquires a permit from this semaphore, blocking until one is available, or the thread is interrupted. acquire() throws the InterruptedException and must be used in a try-catch block.

• void release() Releases a permit, returning it to the semaphore. No exception is thrown by this method.

3/4

1. 2. class TeaDrinker implements Runnable { 3. private int myID; 4. private int mySleepTimeNS; 5. public TeaDrinker(int id, int sleep) { 6. myID = id; 7. mySleepTimeNS = sleep; 8. } 9. private void sleep(int t) { 10. try { 11. Thread.sleep(t); 12. } catch (InterruptedException ie) { 13. System.out.println("Sleep interrupted; should not happen"); 14. } 15. } 16. public void run() { 17. System.out.println("Tea drinker " + myID + 18. " starting after sleep of " + mySleepTimeNS + "ns"); 19. sleep(mySleepTimeNS); 20. while (true) { // run for ever 21. sleep(mySleepTimeNS); 22. System.out.println("Tea drinker " + myID + 23. " getting cup, saucer, and spoon"); 24. // add code to get the cup, saucer, and spoon here 25. System.out.println("Tea drinker " + myID + 26. " drinking tea for " + mySleepTimeNS + "ns"); 27. sleep(mySleepTimeNS); 28. System.out.println("Tea drinker " + myID + 29. " finished drinking tea, " + 30. "releasing cup, saucer, and spoon"); 31. // add code to release the cup, saucer, and spoon here 32. System.out.println("Tea drinker " + myID + 33. " will talk for " + mySleepTimeNS + "ns"); 34. sleep(mySleepTimeNS); 35. } 36. } 37. }

Prof. Pitts CS554AH2: Operating Systems Spring 2020

Part 3: In this program, you'll write five separate Runnable classes:

• one class, Reader, reads a line of text from System.in and places it in a shared String variable

• one class, CCounter, looks at the shared String and places the number of characters in a shared character count variable

• one class, VCounter, looks at the shared String and places the number of vowels in the string in a shared vowel count variable

• one class, DCounter, looks at the shared String and places the number of digits in the string in a share digit count variable

• one class, Displayer, uses the shared String , character count, vowel count, and digit count variable to display (using System.out.println) the original string, the total number of characters, the number of vowels and digits in the string

The threads have a dependency graph that looks like this:

This graph means that CCounter, VCounter, adn DCounter cannot not begin work until Reader has put a new string in the share String variable. Displayer cannot begin work until all three of CCounter, VCounter, and DCounter have placed their respective counts in the three shared variables. An after it has read the first string to begin the sequence, Reader must wait until Displayer has displayer the current string and counts before it reads the next string.

This is similar to the example we saw a few weeks ago in which we divided that calculation of the perimeter of a circle into four threads.

The run methods of each of the Runnable classes should have a forever while loop and should use semaphores to sequence the threads properly. Use the semaphore version of the circle circumference program as an example.

Write a public class called WorkFlow with the five Runnable classes above as inner classes. The main method of WorkFlow should create and start each of the threads. You should then be able to type lines and see the proper display for each line.

You can code each of the run methods to break out of the while loop if the string is QUIT, but be careful to release the necessary semaphores in the break condition to allow the other threads to quit.

Your WorkFlow class and all of the inner classes should be in a file called WorkFlow.java.

4/4

Reader

CCounter

VCounter

DCounter

Displayer