CSCI 4534 - Operating Systems

Assignment 1 Clarifications

Q: How can I get the point for those questions that ask me how much time I spent on a task?

A: Answer truthfully. Exclude time spent getting sidetracked (e.g. reading email, etc.). All (relevant and believable) answers are acceptable, such as 10 minutes, an hour, 10 hours. Examples of unacceptable answers are: "too much", "more than I should have", "time is relative", "all my youth".


Q: When working on a task that asks me to implement a class, may I change one of the provided non-stub classes and/or interfaces to fit the needs of my modified class?

A: No, you may not. You should only change the one file containing the one class you are asked to implement, or possibly add new classes. When your assignment is graded, the instructor will use his own copies of the provided classes so any changes you make will be ignored. As a result, your code may not compile or run, in which case you will get a 0 for the task.


Q: Are we supposed to create one thread for each numeric input to the compute server or one thread for each job?

A: One thread per job. If a job has more than one numeric input, they are processed by the same thread, one after another.


Q: When we send an implementation of Calculator from the client to the compute server, are we sending an object instance and/or the class definition itself and/or the class name?

A: We are only sending a serialized instance, which comprises (in some internal Java format) the class name and the values of the instance variables for that particular object (if any). We are not sending across the byte code containing the class definition. In other words, if we send an instance of a class which is not in the classpath of the server, then the server will throw a ClassNotFoundException. For example, if you have BitCalculator on the client machine, but BitCalculator is not on the server machine, then the server will reject BitCalculator. Note that this is a limitation of our software. Java provides many easy-to-use facilities to send across class definitions. We are not using them in this assignment to keep it simple.

We are also not sending just the class name as a string because that would be simplistic: if there were instance variables, we'd have to send them manually too, which would require a long switch on the class name. In effect we'd be creating our own serialization protocol. Instead, we use Java's.


Q: I tried to run runclient.bat with 8 numeric inputs, but the last input was ignored. Is this a bug?

A: It is a limitation of the Windows batch file syntax. A Windows batch file refers to its command-line arguments using the syntax %n where n is between 1 and 9. This means that there is no way to access any remaining arguments. If you supply more than 7 numeric inputs to runclient.bat, you have entered a total of 9 command-line arguments to the script, so any additional ones are ignored. If you want to run the client with more than 7 inputs, just execute the JVM directly, without using runclient.bat.


Q: When we add multi-threading to SocketServer, can we create a new class to represent the new thread?

A: Yes, you may. You can create a new public class, or create an inner class within SocketServer. You may also have SocketServer implement Runnable. In general, feel free to add more classes than those provided when completing an assignment, or have provided stubs (i.e. provided partial implementations) implement additional interfaces.


Q: The assignment calls for incremental improvements to SocketServer. Do we have to submit multiple versions of the class for each incremental change?

A: No. Just submit the final version that contains as many of the improvements as you were able to implement.


Q: When I run
runclient.bat localhost:5135 EndCalculator
I get an exception. Isn't this how I'm supposed to stop the server?

A: No. Do not use runclient.bat to stop the server; use stopserver.bat instead, as documented in the assignment requirements. In principle, an alternative solution is to move EndCalculator into the calculator package; but since you are not allowed to move around provided classes, you cannot do this. Incidentally, the reason EndCalculator is in the server package is because it's a dummy class: it doesn't perform any real computation; it's only reason for existence is to stop the server, and hence it is packaged with the server. Alternative designs (with alternative justifications) would also have been reasonable; the choice we made is largely a stylistic one.


Q: What is the correct behaviour if the multi-threaded compute server is running a job on behalf of one client, and at that time another client sends an instance of EndCalculator?

A: The server should stop listening for additional connections, clean up socket resources, and return from the serve() method. The server should not call System.exit(), nor should it do anything to all active, on-going computations on its other threads; so do not call Thread.stop() or bother those threads in any other way. Here is what happens when serve() returns: the main thread of the server ends but the JVM does not exit yet. As long as other threads are running, the JVM waits for them to finish. So the earlier job(s) is (are) still being processed, and when eventually they all send their responses to their respective clients, the JVM will automatically terminate.


Q: Why are we implementing only a nonpreemptive SJF scheduler? What about a preemptive one (shortest-remaining-time-first; SRTF)? Similarly for priority scheduling.

A: The provided simulator framework could be used to compute the average waiting time under SRTF scheduling. However this is not part of the assignment just because the assignment is long enough as it stands. If you are interested, feel free to implement one and thus enhance your understanding of the preemptive algorithm; it it truly a matter of 5 extra minutes of effort after you have SJF done. But you won't receive additional points. The provided assignment answers include such a scheduler.

The same answer applies to priority scheduling except that the provided assignment answers do not include a scheduler with preemptive priority scheduling (but again you can write one in less than 5 minutes given its nonpreemptive counterpart).


Q: Are we supposed to address starvation in RRScheduler?

A: The short answer is: no, you need not worry about it. Here is the long answer:

Starvation can occur in the following scenario: suppose process P1 is on the CPU. While it's running, P2 arrives, so when P1 reaches the end of its time slice and gets preempted, we schedule P2. While P2 is on the CPU, P3 arrives, so when P2 reaches the end of its time slice and gets preempted, we schedule P3. And so on: as long as new processes arrive, we never go back to the beginning of the queue to schedule P1 (or P2, and so on) again! In effect, P1 is starved.

This is not a problem in practice. It is very unlikely to encounter such a high rate (one per quantum) stream of processes, even if we allow for old processes returning from I/O. So starvation is much less likely than it is in the case of static priority scheduling which lets a high priority process use the CPU for as long as it needs, without preemption (and where starvation can occur with an arrival late as low as one new high priority process arriving during the full execution of the current one). In practice, the medium-term scheduler would intervene to reduce the degree of multiprogramming.

Moreover, techniques to address such starvation are complex and impractical: if that many processes arrive that fast, then even a fairer algorithm will schedule each process very infrequently. The system would appear unresponsive and as good as dead so it'd get rebooted (unless the medium-term scheduler intervenes). Worse, a complex scheduling algorithm would increase the context switch time (and system overhead) even under regular operation. Hence, in practice, we just don't worry about starvation under such unlikely scenarios: we focus on optimizing the common case instead.


© 2004 Apostolos Lerios