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

📄 synch.cc

📁 美国加州大学操作系统课程实验平台Nachos
💻 CC
字号:
// synch.cc //	Routines for synchronizing threads.  Three kinds of//	synchronization routines are defined here: semaphores, locks //   	and condition variables.//// Any implementation of a synchronization routine needs some// primitive atomic operation.  We assume Nachos is running on// a uniprocessor, and thus atomicity can be provided by// turning off interrupts.  While interrupts are disabled, no// context switch can occur, and thus the current thread is guaranteed// to hold the CPU throughout, until interrupts are reenabled.//// Because some of these routines might be called with interrupts// already disabled (Semaphore::V for one), instead of turning// on interrupts at the end of the atomic operation, we always simply// re-set the interrupt state back to its original value (whether// that be disabled or enabled).//// Once we'e implemented one set of higher level atomic operations,// we can implement others using that implementation.  We illustrate// this by implementing locks and condition variables on top of // semaphores, instead of directly enabling and disabling interrupts.//// Locks are implemented using a semaphore to keep track of// whether the lock is held or not -- a semaphore value of 0 means// the lock is busy; a semaphore value of 1 means the lock is free.//// The implementation of condition variables using semaphores is// a bit trickier, as explained below under Condition::Wait.//// Copyright (c) 1992-1996 The Regents of the University of California.// All rights reserved.  See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions.#include "copyright.h"#include "synch.h"#include "main.h"//----------------------------------------------------------------------// Semaphore::Semaphore// 	Initialize a semaphore, so that it can be used for synchronization.////	"debugName" is an arbitrary name, useful for debugging.//	"initialValue" is the initial value of the semaphore.//----------------------------------------------------------------------Semaphore::Semaphore(char* debugName, int initialValue){    name = debugName;    value = initialValue;    queue = new List<Thread *>;}//----------------------------------------------------------------------// Semaphore::Semaphore// 	De-allocate semaphore, when no longer needed.  Assume no one//	is still waiting on the semaphore!//----------------------------------------------------------------------Semaphore::~Semaphore(){    delete queue;}//----------------------------------------------------------------------// Semaphore::P// 	Wait until semaphore value > 0, then decrement.  Checking the//	value and decrementing must be done atomically, so we//	need to disable interrupts before checking the value.////	Note that Thread::Sleep assumes that interrupts are disabled//	when it is called.//----------------------------------------------------------------------voidSemaphore::P(){    Interrupt *interrupt = kernel->interrupt;    Thread *currentThread = kernel->currentThread;        // disable interrupts    IntStatus oldLevel = interrupt->SetLevel(IntOff);	        while (value == 0) { 		// semaphore not available	queue->Append(currentThread);	// so go to sleep	currentThread->Sleep(FALSE);    }     value--; 			// semaphore available, consume its value       // re-enable interrupts    (void) interrupt->SetLevel(oldLevel);	}//----------------------------------------------------------------------// Semaphore::V// 	Increment semaphore value, waking up a waiter if necessary.//	As with P(), this operation must be atomic, so we need to disable//	interrupts.  Scheduler::ReadyToRun() assumes that interrupts//	are disabled when it is called.//----------------------------------------------------------------------voidSemaphore::V(){    Interrupt *interrupt = kernel->interrupt;        // disable interrupts    IntStatus oldLevel = interrupt->SetLevel(IntOff);	        if (!queue->IsEmpty()) {  // make thread ready.	kernel->scheduler->ReadyToRun(queue->RemoveFront());    }    value++;        // re-enable interrupts    (void) interrupt->SetLevel(oldLevel);}//----------------------------------------------------------------------// Semaphore::SelfTest, SelfTestHelper// 	Test the semaphore implementation, by using a semaphore//	to control two threads ping-ponging back and forth.//----------------------------------------------------------------------static Semaphore *ping;static voidSelfTestHelper (Semaphore *pong) {    for (int i = 0; i < 10; i++) {        ping->P();	pong->V();    }}voidSemaphore::SelfTest(){    Thread *helper = new Thread("ping");    ASSERT(value == 0);		// otherwise test won't work!    ping = new Semaphore("ping", 0);    helper->Fork((VoidFunctionPtr) SelfTestHelper, this);    for (int i = 0; i < 10; i++) {        ping->V();	this->P();    }    delete ping;}//----------------------------------------------------------------------// Lock::Lock// 	Initialize a lock, so that it can be used for synchronization.//	Initially, unlocked.////	"debugName" is an arbitrary name, useful for debugging.//----------------------------------------------------------------------Lock::Lock(char* debugName){    name = debugName;    semaphore = new Semaphore("lock", 1);  // initially, unlocked    lockHolder = NULL;}//----------------------------------------------------------------------// Lock::~Lock// 	Deallocate a lock//----------------------------------------------------------------------Lock::~Lock(){    delete semaphore;}//----------------------------------------------------------------------// Lock::Acquire//	Atomically wait until the lock is free, then set it to busy.//	Equivalent to Semaphore::P(), with the semaphore value of 0//	equal to busy, and semaphore value of 1 equal to free.//----------------------------------------------------------------------void Lock::Acquire(){    semaphore->P();    lockHolder = kernel->currentThread;}//----------------------------------------------------------------------// Lock::Release//	Atomically set lock to be free, waking up a thread waiting//	for the lock, if any.//	Equivalent to Semaphore::V(), with the semaphore value of 0//	equal to busy, and semaphore value of 1 equal to free.////	By convention, only the thread that acquired the lock// 	may release it.//---------------------------------------------------------------------void Lock::Release(){    ASSERT(IsHeldByCurrentThread());    lockHolder = NULL;    semaphore->V();}//----------------------------------------------------------------------// Condition::Condition// 	Initialize a condition variable, so that it can be //	used for synchronization.  Initially, no one is waiting//	on the condition.////	"debugName" is an arbitrary name, useful for debugging.//----------------------------------------------------------------------Condition::Condition(char* debugName){    name = debugName;    waitQueue = new List<Semaphore *>;}//----------------------------------------------------------------------// Condition::Condition// 	Deallocate the data structures implementing a condition variable.//----------------------------------------------------------------------Condition::~Condition(){    delete waitQueue;}//----------------------------------------------------------------------// Condition::Wait// 	Atomically release monitor lock and go to sleep.//	Our implementation uses semaphores to implement this, by//	allocating a semaphore for each waiting thread.  The signaller//	will V() this semaphore, so there is no chance the waiter//	will miss the signal, even though the lock is released before//	calling P().////	Note: we assume Mesa-style semantics, which means that the//	waiter must re-acquire the monitor lock when waking up.////	"conditionLock" -- lock protecting the use of this condition//----------------------------------------------------------------------void Condition::Wait(Lock* conditionLock) {     Semaphore *waiter;         ASSERT(conditionLock->IsHeldByCurrentThread());     waiter = new Semaphore("condition", 0);     waitQueue->Append(waiter);     conditionLock->Release();     waiter->P();     conditionLock->Acquire();     delete waiter;}//----------------------------------------------------------------------// Condition::Signal// 	Wake up a thread waiting on this condition, if any.////	Note: we assume Mesa-style semantics, which means that the//	signaller doesn't give up control immediately to the thread//	being woken up (unlike Hoare-style).////	Also note: we assume the caller holds the monitor lock//	(unlike what is described in Birrell's paper).  This allows//	us to access waitQueue without disabling interrupts.////	"conditionLock" -- lock protecting the use of this condition//----------------------------------------------------------------------void Condition::Signal(Lock* conditionLock){    Semaphore *waiter;        ASSERT(conditionLock->IsHeldByCurrentThread());        if (!waitQueue->IsEmpty()) {        waiter = waitQueue->RemoveFront();	waiter->V();    }}//----------------------------------------------------------------------// Condition::Broadcast// 	Wake up all threads waiting on this condition, if any.////	"conditionLock" -- lock protecting the use of this condition//----------------------------------------------------------------------void Condition::Broadcast(Lock* conditionLock) {    while (!waitQueue->IsEmpty()) {        Signal(conditionLock);    }}

⌨️ 快捷键说明

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