CSC 407 Homework #4
Total Page:16
File Type:pdf, Size:1020Kb
CSC 407/507 Homework #6 answer key 1) a. Using the semaphore, as covered in the notes, we can implement cooperative and competitive synchronization by using either a single semaphore to guard access to the shared data for competitive synchronization, or use 3 semaphores (full, empty, access) for cooperative synchronization (although in this case, full and empty are int sempahores, not binary). To implement a rendezvous is a little more tricky. We need the first process to wait until the second has caught up. We might implement it as follows. Set the semaphore to 2. Implement wait as: semaphore--; while(semaphore>0); The problem here is that this causes a process to wait for exactly one other process. If a rendezvous requires that a process wait for a specific other process, or if there are many processes any of whom may satisfy the rendezvous, we need something more elaborate that the semaphore cannot handle. b. The monitor in Concurrent Pascal automatically implements competitive synchronization in that, like using a semaphore, will only permit one process to access the shared datum until it is through with it. For cooperative synchronization, we may need some kind of additional bookkeeping mechanism. We might do this by implementing something like the integer semaphore and while(…); loop inside our code that accesses the shared datum and thus recreate the semaphore on top of the monitor. The rendezvous would similarly have to be implemented on top of the monitor. c. In Ada 83, we have the accept clause which receives optional parameters. The accept clause ensures competitive synchronization without any additional effort. To add cooperative synchronization, we use something like an integer semaphore and a conditional to test when access can be granted. The book demonstrates this as follows: when not Full(Buffer) => accept Deposit(…) do … end Here, we are relying on the ADT that implements Buffer to tell us when it is not full and if and if full, the instruction suspends. For rendezvous, we can use the optional parameters for the accept clause to include the process that is sending the rendezvous signal. In this way, we can define a when clause that only executes when the parameter matches the process that this process is waiting on for the rendezvous. d. For Java, the modifier synchronized ensures that the method only executes in a mutually exclusive manner and thus is all we need to implement competitive synchronization. For cooperative synchronization, we pass another thread the message notify to indicate that this thread has reached a point where the other thread can now continue. If there are multiple other threads to contact, we use notifyAll. We can use the exact same mechanism (notify) for a rendezvous. 2) a. Case 1 results in possible data corruption because we are not ensuring that the producer produce or the consumer consume in a mutually exclusive way. b. Case 2 results in deadlock in that the producer is decrementing empty instead of full when inserting a value so that ultimately, the buffer might have items in it but the consumer believes it is full and the consumer is decrementing full when consuming an item which might lead the producer to believe the buffer is full when it has empty spots. 3) Master co-routine create four player (player(1) .. player(4)) co-routines, each with its own buffer done = false do { generate the 52 cards and distribute them to the four players via their individual buffers turn = 13 select starting player i do { invoke player i ////// players play 1 card each determine winner of hand, update scores, turn-- }while(turn>0); determine winner of round, update scores if any player has won the game output winner destroy all four player co-routines set done to true }while(!done); Player(i): select card and play it if((i+1)%4==0) resume master else resume player(i+1) 4) File not found, I/O error, array subscript out of range, division by 0, printer jam, printer out of paper. I would definitely handle the I/O error and file not found error via exception handling. I would use logic to ensure no subscript out of range error and no division by 0 error rather than relying on exception handling. I would not bother with a printer error as that seems unlikely. 5) a. PL/I ON ARITHMETICEXCEPTION GO TO error; BEGIN GET X; Y = SQRT(X); PUT SKIP LIST (Y); GO TO next; END; error: PUT SKIP LIST “ERROR, input negative”; next: b. Ada Get(X); Y := SQRT(X); Put(Y); exception when Arithmetic_Error => Put(“Error, input negative”); c. C++ (assume x is an int) cin >> x; try { if(x<0) throw(1); y = sqrt(x); cout << y; } catch(int x) { cout << “Error, input negative”; } 6) Java – the built-in exceptions makes it superior to C++ since exceptions can be thrown by the run-time environment rather than being explicitly raised. This makes the facility more useful and thus the language more reliable. The notion of a try/catch/finally block also makes exception handling more writable. C++ does not make use of a finally block. PL/I – although the language’s exception handling facilities are complex, it is still more writable than C++ because of built-in and user-defined exceptions that can be raised automatically or explicitly. But PL/I’s continuation is more complex than Java’s making the language’s EH facilities less convenient and reliable. We might say the PL/I’s EH is more writable since there are more options but I prefer Java especially with the finally clause. C++ - the poorest of the bunch because you must explicitly throw any exception basically making EH little more than writing your own conditional logic. The only positive is that it causes the current try block to terminate. Consider the following, assuming x is an int and y is a float: try { … // some code here if(some condition) throw(x); else if (some other condition) throw(y); … // more code here } catch(int x) {…} catch(float y) {…} This could be rewritten as … // some code here if(some condition) {…} (same code as the first catch block) else if (some other condition) {…} (same code as the second catch block) else // more code here So there is little value to the C++ EH facility other than using it as a glorified GO TO to skip a set of code. It offers little in the way of reliability or convenience and only marginally might improve readability. As far as writability, it is the poorest of the three languages. .