⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kthread.java

📁 Nachos 5 java version
💻 JAVA
字号:
package nachos.threads;import nachos.machine.*;/** * A KThread is a thread that can be used to execute Nachos kernel code. Nachos * allows multiple threads to run concurrently. * * To create a new thread of execution, first declare a class that implements * the <tt>Runnable</tt> interface. That class then implements the <tt>run</tt> * method. An instance of the class can then be allocated, passed as an * argument when creating <tt>KThread</tt>, and forked. For example, a thread * that computes pi could be written as follows: * * <p><blockquote><pre> * class PiRun implements Runnable { *     public void run() { *         // compute pi *         ... *     } * } * </pre></blockquote> * <p>The following code would then create a thread and start it running: * * <p><blockquote><pre> * PiRun p = new PiRun(); * new KThread(p).fork(); * </pre></blockquote> */public class KThread {    /**     * Get the current thread.     *     * @return	the current thread.     */    public static KThread currentThread() {	Lib.assert(currentThread != null);	return currentThread;    }        /**     * Allocate a new <tt>KThread</tt>. If this is the first <tt>KThread</tt>,     * create an idle thread as well.     */    public KThread() {	if (currentThread != null) {	    tcb = new TCB();	}	    	else {	    readyQueue = ThreadedKernel.scheduler.newThreadQueue(false);	    readyQueue.acquire(this);	    	    currentThread = this;	    tcb = TCB.currentTCB();	    name = "main";	    restoreState();	    createIdleThread();	}    }    /**     * Allocate a new KThread.     *     * @param	target	the object whose <tt>run</tt> method is called.     */    public KThread(Runnable target) {	this();	this.target = target;    }    /**     * Set the target of this thread.     *     * @param	target	the object whose <tt>run</tt> method is called.     * @return	this thread.     */    public KThread setTarget(Runnable target) {	Lib.assert(status == statusNew);		this.target = target;	return this;    }    /**     * Set the name of this thread. This name is used for debugging purposes     * only.     *     * @param	name	the name to give to this thread.     * @return	this thread.     */    public KThread setName(String name) {	this.name = name;	return this;    }    /**     * Get the name of this thread. This name is used for debugging purposes     * only.     *     * @return	the name given to this thread.     */         public String getName() {	return name;    }    /**     * Get the full name of this thread. This includes its name along with its     * numerical ID. This name is used for debugging purposes only.     *     * @return	the full name given to this thread.     */    public String toString() {	return (name + " (#" + id + ")");    }    /**     * Deterministically and consistently compare this thread to another     * thread.     */    public int compareTo(Object o) {	KThread thread = (KThread) o;	if (id < thread.id)	    return -1;	else if (id > thread.id)	    return 1;	else	    return 0;    }    /**     * Causes this thread to begin execution. The result is that two threads     * are running concurrently: the current thread (which returns from the     * call to the <tt>fork</tt> method) and the other thread (which executes     * its target's <tt>run</tt> method).     */    public void fork() {	Lib.assert(status == statusNew);	Lib.assert(target != null);		Lib.debug(dbgThread,		  "Forking thread: " + toString() + " Runnable: " + target);	boolean intStatus = Machine.interrupt().disable();	tcb.start(new Runnable() {		public void run() {		    runThread();		}	    });	ready();		Machine.interrupt().restore(intStatus);    }    private void runThread() {	begin();	target.run();	finish();    }    private void begin() {	Lib.debug(dbgThread, "Beginning thread: " + toString());		Lib.assert(this == currentThread);	restoreState();	Machine.interrupt().enable();    }    /**     * Finish the current thread and schedule it to be destroyed when it is     * safe to do so. This method is automatically called when a thread's     * <tt>run</tt> method returns, but it may also be called directly.     *     * The current thread cannot be immediately destroyed because its stack and     * other execution state are still in use. Instead, this thread will be     * destroyed automatically by the next thread to run, when it is safe to     * delete this thread.     */    public static void finish() {	Lib.debug(dbgThread, "Finishing thread: " + currentThread.toString());		Machine.interrupt().disable();	Machine.autoGrader().finishingCurrentThread();	Lib.assert(toBeDestroyed == null);	toBeDestroyed = currentThread;	currentThread.status = statusFinished;		sleep();    }    /**     * Relinquish the CPU if any other thread is ready to run. If so, put the     * current thread on the ready queue, so that it will eventually be     * rescheuled.     *     * <p>     * Returns immediately if no other thread is ready to run. Otherwise     * returns when the current thread is chosen to run again by     * <tt>readyQueue.nextThread()</tt>.     *     * <p>     * Interrupts are disabled, so that the current thread can atomically add     * itself to the ready queue and switch to the next thread. On return,     * restores interrupts to the previous state, in case <tt>yield()</tt> was     * called with interrupts disabled.     */    public static void yield() {	Lib.debug(dbgThread, "Yielding thread: " + currentThread.toString());		Lib.assert(currentThread.status == statusRunning);		boolean intStatus = Machine.interrupt().disable();	currentThread.ready();	runNextThread();		Machine.interrupt().restore(intStatus);    }    /**     * Relinquish the CPU, because the current thread has either finished or it     * is blocked. This thread must be the current thread.     *     * <p>     * If the current thread is blocked (on a synchronization primitive, i.e.     * a <tt>Semaphore</tt>, <tt>Lock</tt>, or <tt>Condition</tt>), eventually     * some thread will wake this thread up, putting it back on the ready queue     * so that it can be rescheduled. Otherwise, <tt>finish()</tt> should have     * scheduled this thread to be destroyed by the next thread to run.     */    public static void sleep() {	Lib.debug(dbgThread, "Sleeping thread: " + currentThread.toString());		Lib.assert(Machine.interrupt().disabled());	if (currentThread.status != statusFinished)	    currentThread.status = statusBlocked;	runNextThread();    }    /**     * Moves this thread to the ready state and adds this to the scheduler's     * ready queue.     */    public void ready() {	Lib.debug(dbgThread, "Ready thread: " + toString());		Lib.assert(Machine.interrupt().disabled());	Lib.assert(status != statusReady);		status = statusReady;	if (this != idleThread)	    readyQueue.waitForAccess(this);		Machine.autoGrader().readyThread(this);    }    /**     * Waits for this thread to finish. If this thread is already finished,     * return immediately. This method must only be called once; the second     * call is not guaranteed to return. This thread must not be the current     * thread.     */    public void join() {	Lib.debug(dbgThread, "Joining to thread: " + toString());	Lib.assert(this != currentThread);    }    /**     * Create the idle thread. Whenever there are no threads ready to be run,     * and <tt>runNextThread()</tt> is called, it will run the idle thread. The     * idle thread must never block, and it will only be allowed to run when     * all other threads are blocked.     *     * <p>     * Note that <tt>ready()</tt> never adds the idle thread to the ready set.     */    private static void createIdleThread() {	Lib.assert(idleThread == null);		idleThread = new KThread(new Runnable() {	    public void run() { while (true) yield(); }	});	idleThread.setName("idle");	Machine.autoGrader().setIdleThread(idleThread);		idleThread.fork();    }        /**     * Determine the next thread to run, then dispatch the CPU to the thread     * using <tt>run()</tt>.     */    private static void runNextThread() {	KThread nextThread = readyQueue.nextThread();	if (nextThread == null)	    nextThread = idleThread;	nextThread.run();    }    /**     * Dispatch the CPU to this thread. Save the state of the current thread,     * switch to the new thread by calling <tt>TCB.contextSwitch()</tt>, and     * load the state of the new thread. The new thread becomes the current     * thread.     *     * <p>     * If the new thread and the old thread are the same, this method must     * still call <tt>saveState()</tt>, <tt>contextSwitch()</tt>, and     * <tt>restoreState()</tt>.     *     * <p>     * The state of the previously running thread must already have been     * changed from running to blocked or ready (depending on whether the     * thread is sleeping or yielding).     *     * @param	finishing	<tt>true</tt> if the current thread is     *				finished, and should be destroyed by the new     *				thread.     */    private void run() {	Lib.assert(Machine.interrupt().disabled());	Machine.yield();	currentThread.saveState();	Lib.debug(dbgThread, "Switching from: " + currentThread.toString()		  + " to: " + toString());	currentThread = this;	tcb.contextSwitch();	currentThread.restoreState();    }    /**     * Prepare this thread to be run. Set <tt>status</tt> to     * <tt>statusRunning</tt> and check <tt>toBeDestroyed</tt>.     */    protected void restoreState() {	Lib.debug(dbgThread, "Running thread: " + currentThread.toString());		Lib.assert(Machine.interrupt().disabled());	Lib.assert(this == currentThread);	Lib.assert(tcb == TCB.currentTCB());	Machine.autoGrader().runningThread(this);		status = statusRunning;	if (toBeDestroyed != null) {	    toBeDestroyed.tcb.destroy();	    toBeDestroyed.tcb = null;	    toBeDestroyed = null;	}    }    /**     * Prepare this thread to give up the processor. Kernel threads do not     * need to do anything here.     */    protected void saveState() {	Lib.assert(Machine.interrupt().disabled());	Lib.assert(this == currentThread);    }    private static class PingTest implements Runnable {	PingTest(int which) {	    this.which = which;	}		public void run() {	    for (int i=0; i<5; i++) {		System.out.println("*** thread " + which + " looped "				   + i + " times");		currentThread.yield();	    }	}	private int which;    }    /**     * Tests whether this module is working.     */    public static void selfTest() {	Lib.debug(dbgThread, "Enter KThread.selfTest");		new KThread(new PingTest(1)).setName("forked thread").fork();	new PingTest(0).run();    }    private static final char dbgThread = 't';    /**     * Additional state used by schedulers.     *     * @see	nachos.threads.PriorityScheduler.ThreadState     */    public Object schedulingState = null;    private static final int statusNew = 0;    private static final int statusReady = 1;    private static final int statusRunning = 2;    private static final int statusBlocked = 3;    private static final int statusFinished = 4;    /**     * The status of this thread. A thread can either be new (not yet forked),     * ready (on the ready queue but not running), running, or blocked (not     * on the ready queue and not running).     */    private int status = statusNew;    private String name = "(unnamed thread)";    private Runnable target;    private TCB tcb;    /**     * Unique identifer for this thread. Used to deterministically compare     * threads.     */    private int id = numCreated++;    /** Number of times the KThread constructor was called. */    private static int numCreated = 0;    private static ThreadQueue readyQueue = null;    private static KThread currentThread = null;    private static KThread toBeDestroyed = null;    private static KThread idleThread = null;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -