CSS 430
Program 2: Scheduler
Duedate: See the syllabus
The suspend( ) method suspends a target thread, whereas the resume( ) method resumes a suspended thread. These methods are not system-dependent. No matter what operating systems you use, a target thread is suspended and resumed immediately. In order to implement a rigid round-robin CPU scheduling, we could modify ThreadOS Scheduler to dequeue a front user thread from its circular list, to resume it with the resume method, and to suspend it with the suspend method after a execution quantum has been expired. However, suspend and resume may cause a deadlock if a suspended thread holds a lock and a runnable thread tries to acquire this lock. To avoid any deadlocks, we must pay our closest attention when using them with synchronized, wait( ) and notify( ) keywords. (They will be taught in the assignment 3 to realize inter-threads synchronization.) When you peek Scheduler.java, you see some synchronized keywords in it. Don't remove them or put additional synchronized keywords, otherwise your Scheduler.java will easily fall into a deadlock.
When you compile Java programs that use deprecated methods such as suspend( ) and resume, you must compile them with a -deprecation option. Although the javac compiler will print out some warning messages, just ignore them in the assignment 2.
uw1-320-00% javac -deprecation Scheduler.java
./Scheduler.java:128: warning: resume() in java.lang.Thread has been deprecated
currentThread.resume( );
^
./Scheduler.java:136: warning: suspend() in java.lang.Thread has been deprecated
currentThread.suspend( );
^
2 warnings
uw1-320-00%
| Data members | Descriptions |
| private Vector queue; | a list of all active threads, (to be specific, TCBs). |
| private int timeSlice; | a time slice allocated to each user thread execution |
| private static final int DEFAULT_TIME_SLICE = 1000; | the unit is millisecond. Thus 1000 means 1 second. |
| private boolean[] tids; | Each array entry indicates that the corresponding thread ID has been used if the entry value is true. |
| private static final int DEFAULT_MAX_THREADS = 10000; | tids[] has 10000 elements |
| Methods | Descriptions |
| private void initTid( int maxThreads ) | allocates the tid[] array with a maxThreads number of elements |
| private int getNewTid( ) | finds an tid[] array element whose value is false, and returns its index as a new thread ID. |
| private boolean returnTid( int tid ) | sets the corresponding tid[] element, (i.e., tid[tid]) false. The return value is false if tid[tid] is already false, (i.e., if this tid has not been used), otherwise true. |
| public int getMaxThreads( ) | returns the length of the tid[] array, (i.e., the available number of threads). |
| public TCB getMyTcb( ) | finds the current thread's TCB from the active thread queue and returns it |
| public Scheduler(int quantum, int maxThreads) | receives two arguments: (1) the time slice allocated to each thread execution and (2) the maximal number of threads to be spawned, (namely the length of tid[]). It creates an active thread queue and initializes the tid[] array |
| private void schedulerSleep( ) | puts the Scheduler to sleep for a given time quantum |
| public TCB addThread( Thread t ) | allocates a new TCB to this thread t and adds the TCB to the active thread queue. This new TCB receives the calling thread's id as its parent id. |
| public boolean deleteThread( ) | finds the current thread's TCB from the active thread queue and marks its TCB as terminated. The actual deletion of a terminated TCB is performed inside the run( ) method, (in order to prevent race conditions). |
| public void sleepThread( int milliseconds ) | puts the calling thread to sleep for a given time quantum. |
| public void run( ) | This is the heart of Scheduler. The difference from the lecture slide includes: (1) retrieving a next available TCB rather than a thread from the active thread list, (2) deleting it if it has been marked as "terminated", and (3) starting the thread if it has not yet been started. Other than this difference, the Scheduler repeats retrieving a next available TCB from the list, raising up the corresponding thread's priority, yielding CPU to this thread with sleep( ), and lowering the thread's priority. |
The scheduler itself is started by ThreadOS Kernel. It creates a thread queue that maintains all user threads invoked by the SysLib.exec( String args[] ) system call. Upon receiving this system call, ThreadOS Kernel instantiates a user thread and calls the scheduler's addThread( Thread t ) method. A new TCB is allocated to this thread and enqueued in the scheduler's thread list. The scheduler repeats an infinite while loop in its run method. It picks up a next available TCB from the list. If the thread in this TCB has not yet been activated (but instantiated), the scheduler starts it first. It thereafter raises up the thread's priority to execute for a given time slice.
When a user thread calls SysLib.exit( ) to terminate itself, the Kernel calls the scheduler's deleteThread( ) in order to mark this thread's TCB as terminated. When the scheduler dequeues this TCB from the circular queue and finds out that it has been marked as terminated, it deletes this TCB.
$ java boot
threadOS ver 1.0:
Type ? for help
threadOS: a new thread (thread=Thread[Thread-3,2,main] tid=0 pid=-1)
-->l Test2b
l Test2b
threadOS: a new thread (thread=Thread[Thread-6,2,main] tid=1 pid=0)
threadOS: a new thread (thread=Thread[Thread-8,2,main] tid=2 pid=1)
threadOS: a new thread (thread=Thread[Thread-10,2,main] tid=3 pid=1)
threadOS: a new thread (thread=Thread[Thread-12,2,main] tid=4 pid=1)
threadOS: a new thread (thread=Thread[Thread-14,2,main] tid=5 pid=1)
threadOS: a new thread (thread=Thread[Thread-16,2,main] tid=6 pid=1)
Thread[a] is running
....
Test2b spawns five child threads from TestThread2b, each
named Thread[a], Thread[b], Thread[c],
Thread[d], and Thread[e]. They prints out
"Thread[name] is running" every 0.1 second. If the round-robin
schedule is rigidly enforced to give a 1-second time quantum to each
thread, you should see each thread printing out the same message about
10 times consecutively:
Thread[a] is running
Thread[a] is running
Thread[a] is running
Thread[a] is running
Thread[a] is running
Thread[a] is running
Thread[a] is running
Thread[a] is running
Thread[a] is running
Thread[a] is running
Thread[b] is running
Thread[b] is running
....
....
However, messages will be mixed up on your display. Now, modify this
ThreadOS' Scheduler.java code using suspend( )
and resume( ). The modification will be:
$ java boot
threadOS ver 1.0:
Type ? for help
threadOS: a new thread (thread=Thread[Thread-3,2,main] tid=0 pid=-1)
-->l Test2
Similar to Test2b, Test2 spawns five child threads from
TestThread2b, each named Thread[a], Thread[b],
Thread[c], Thread[d], and Thread[e]. They prints
out nothing but their performance data upon their termination:
thread[b]: response time = 2012 turnaround time = 3111 execution time = 1099 thread[e]: response time = 5035 turnaround time = 5585 execution time = 550 ....The following table shows their CPU burst time:
| Thread name | CPU burst (in milliseconds) |
| Thread[a] | 5000 |
| Thread[b] | 1000 |
| Thread[c] | 3000 |
| Thread[d] | 6000 |
| Thread[e] | 500 |