Solution for Exam 2 - Programming Language Technologies and Paradigm | CMSC 433, Exams of Programming Languages

Material Type: Exam; Professor: Hicks; Class: PROG LANG TECH & PDGMS; Subject: Computer Science; University: University of Maryland; Term: Fall 2002;

Typology: Exams

Pre 2010

Uploaded on 02/13/2009

koofers-user-tsj
koofers-user-tsj 🇺🇸

8 documents

1 / 8

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Exam 2
CMSC 433
Programming Language Technologies and Paradigms
Fall 2002
December 3, 2002
Guidelines
Put your name and class account number on each page before starting the exam. Write your answers
directly on the exam sheets, using the back of the page as necessary. I will not accept exams until I ask
for them. If you finish early use the time to recheck your answers. Please be as quiet as possible.
I will not take any questions during the exam. Errors on the exam will be posted on the board as
they are discovered. If you feel an exam question assumes something that is not written, write it down
on your exam sheet. Barring some unforeseen error on the exam, however, you shouldn’t need to do this
at all, so be careful when making assumptions.
Question Points Score
1 25
2 24
3 25
4 26
Total 100
pf3
pf4
pf5
pf8

Partial preview of the text

Download Solution for Exam 2 - Programming Language Technologies and Paradigm | CMSC 433 and more Exams Programming Languages in PDF only on Docsity!

Exam 2

CMSC 433

Programming Language Technologies and Paradigms

Fall 2002

December 3, 2002

Guidelines

Put your name and class account number on each page before starting the exam. Write your answers directly on the exam sheets, using the back of the page as necessary. I will not accept exams until I ask for them. If you finish early use the time to recheck your answers. Please be as quiet as possible. I will not take any questions during the exam. Errors on the exam will be posted on the board as they are discovered. If you feel an exam question assumes something that is not written, write it down on your exam sheet. Barring some unforeseen error on the exam, however, you shouldn’t need to do this at all, so be careful when making assumptions.

Question Points Score

Total 100

  1. (25 points) Short Answer (a sentence or two should be sufficient).

(a) (4 points) How do locks (when used correctly) prevent data races? by ensuring that only one thread can execute code that would modify shared state. (b) (4 points) In addition to preventing data races, what important feature do Java locks provide? They ensure that changes to shared data in one thread are made visible to other threads (c) (6 points) During their lifetime, threads can be in a number of possible states; name two of them. Two of created, runnable, blocked, sleeping, or terminated. (d) (6 points) A state-dependent action within a method requires the object to be in an acceptable state before the action can be performed. For example, to return a value, a queue’s dequeue method requires the queue to be nonempty. Explain two ways that a state-dependent method can respond when the object is not in an acceptable state. Two of:

  • balking (e.g. fail on the attempt by throwing an exception)
  • failing silently (e.g. just return without doing anything)
  • wait until the condition is true
  • wait for a fixed period, then balk
  • balk and retry, or wait for a fixed time and retry, (e) (5 points) Explain how locks create the tension between safety and liveness in multi-threaded programs. Using locks ensures safety by preventing data races. However, locks can also cause deadlock, which inhibits the program from making progress, and thus threatens live- ness.
  • Example 3:

1: class Ex3 { 2: public Log lookupLog(Map map, String name) { 3: Log log = (Log) map.get (name); 4: if (log == null) { 5: log = new LocalLog(100); 6: map.add(name,log); 7: } 8: return log; 9: } 10: } Even when map is synchronized, you can have conflicting writes and read/write. Ex. T1 calls anEx3.lookupLog. name is not in map. map.get returns null. new Log created. T1 gets swapped out. T2 calls anEx3.lookupLog with same name as T had. T2 completes after inserting a new log into map. T1 resumes and inserts its map, overwriting the one inserted by T2.

  1. (Threaded Programming - 25 points). Implement a class MutualExclusionLock having the follow- ing signature:

public class MutualExclusionLock { public synchronized void acquire(); public synchronized void release() throws BadReleaseException; public synchronized boolean attempt(); }

The idea is to implement your own kind of lock that is slightly different from Java’s built-in locks:

(a) To acquire a lock, the program would call acquire(). This will block until the thread can acquire the lock (i.e. until the thread currently holding it releases it). A thread can only hold a lock once. That is, if a thread calls acquire(), and then calls acquire() again, it will block. (b) To release a lock, the program would call release(); this method will throw BadReleaseExcep- tion if a thread other than the one holding the lock tries to release it. (c) To attempt to acquire a lock, the program would call attempt(). If the lock is held by another thread, then attempt() will immediately return false, otherwise it will acquire the lock and return true.

Recall that the method Thread.currentThread() returns the Thread identifier of the currently running thread. Answer:

public class MutualExclusionLock { private Thread holder = null;

/* Just like Java---block until acquiring the lock; unlike Java, the same thread cannot hold the lock more than once. */ public synchronized void acquire() { while (holder != null) { try { wait(); } catch (InterruptedException e) { } } holder = Thread.currentThread(); }

/* Just like Java---release held lock; throws an exception if the wrong thread tries to release the lock */ public synchronized void release() throws BadReleaseException { if (holder != Thread.currentThread()) throw new BadReleaseException(); holder = null; notifyAll(); }

/* Attempt to acquire the lock; return true if successful or false otherwise. Does not block. */ public synchronized boolean attempt() { if (holder == null) { holder = Thread.currentThread(); return true; } else return false; } }

(b) (18 points) Use the bounded thread pool model, in which an executor queues the job to execute, and one or more threads drain the queue to run the jobs. This is similar to the idea of EventThreads in project 4. Implement the PooledExecutor class and a PooledWorkerThread class, using the following Queue interface: public interface Queue { void enqueue(Object o) throws QueueFullException; Object dequeue() throws QueueEmptyException; int currentSize(); int maxSize(); } You can assume that all of the methods of an implementation of Queue will be synchronized methods. More importantly, notice that the queue will not block when consistency conditions are met, but rather will fail by throwing an exception. In particular, if you try to enqueue on a full queue, it will throw an exception; likewise if you try to dequeue from an empty queue, it will throw an exception. Your PooledExecutor class and PooledWorkerThread class will be responsible for handling queue failures and waiting until conditions are acceptable before proceeding. In particular, notice that neither PooledExecutor nor PooledWorkerThread throw QueueFullException or QueueEmptyException. As such, a call to execute() should block while the PooledExecutor’s queue is full, and a similar situation will occur for PooledWorkerThread when the queue is empty. Answer: public class PooledExecutor implements Executor {

private Queue queue;

PooledExecutor(Queue queue, int numPooledThreads) { this.queue = queue; for (int i = 0; i < numPooledThreads ; i++) { (new PooledWorkerThread (queue)).start(); } }

public void execute(Runnable command) { while (true) { synchronized(queue) { try { queue.enqueue(command); queue.notifyAll(); break; } catch (QueueFullException e) { try { queue.wait();} catch (InterruptedException e1) {} } } } } }

public class PooledWorkerThread extends Thread { private Queue queue;

public PooledWorkerThread(Queue queue) { this.queue = queue; }

public void run() { while (true) { synchronized (queue) { try { ((Runnable) queue.dequeue()).run(); queue.notifyAll(); } catch (QueueEmptyException e) { try { queue.wait(); } catch (InterruptedException e1) {} } } } } }