📄 synch-sleep.cc
字号:
// synch.cc // Routines for synchronizing threads. Three kinds of// synchronization routines are defined here: semaphores, locks // and condition variables (the implementation of the last two// are left to the reader).//// 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).//// Copyright (c) 1992-1993 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-sleep.h"#include "system.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;}//----------------------------------------------------------------------// 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(){ IntStatus oldLevel = interrupt->SetLevel(IntOff); // disable interrupts while (value == 0) { // semaphore not available queue->Append((void *)currentThread); // so go to sleep currentThread->Sleep(); } value--; // semaphore available, // consume its value (void) interrupt->SetLevel(oldLevel); // re-enable interrupts}//----------------------------------------------------------------------// 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 threads// are disabled when it is called.//----------------------------------------------------------------------voidSemaphore::V(){ Thread *thread; IntStatus oldLevel = interrupt->SetLevel(IntOff); thread = (Thread *)queue->Remove(); if (thread != NULL) // make thread ready, consuming the V immediately scheduler->ReadyToRun(thread); value++; (void) interrupt->SetLevel(oldLevel);}// Dummy functions -- so we can compile our later assignments // Note -- without a correct implementation of Condition::Wait(), // the test case in the network assignment won't work!*///--------------------------------------------------------------------------Lock::Lock(char* debugName) { name = debugName; now = Free; lockqueue = new List; holdthread = NULL;}//-------------------------------------------------------------------------Lock::~Lock() { delete lockqueue;}//-------------------------------------------------------------------------void Lock::Acquire() { IntStatus oldLevel = interrupt->SetLevel(IntOff); // disable interrupts while (now == Busy) { // semaphore not available lockqueue->Append((void *)currentThread); // so go to sleep currentThread->Sleep(); } DEBUG('t', "thread \"%s\" acquire the lock\n", currentThread->getName()); now = Busy; // lock is available, holdthread = currentThread; // consume its status (void) interrupt->SetLevel(oldLevel); // re-enable interrupts}//-------------------------------------------------------------------------void Lock::Release() { if(isHeldByCurrentThread()){ Thread *thread; IntStatus oldLevel = interrupt->SetLevel(IntOff); thread = (Thread *)lockqueue->Remove(); if (thread != NULL) // make thread ready, consuming the V immediately scheduler->ReadyToRun(thread); DEBUG('t', "thread \"%s\" release the lock\n", currentThread->getName()); now = Free; holdthread = NULL; (void) interrupt->SetLevel(oldLevel); } else return;}//--------------------------------------------------------------------------bool Lock::isHeldByCurrentThread(){ if (holdthread == currentThread)
return TRUE;
else
return FALSE;}//----------------------------------------------------------------------------Condition::Condition(char* debugName) { name = debugName; blockqueue = new List;}//-----------------------------------------------------------------------------Condition::~Condition() { delete blockqueue;}//-----------------------------------------------------------------------------void Condition::Wait(Lock* conditionLock) { //ASSERT(FALSE); IntStatus oldLevel = interrupt->SetLevel(IntOff); conditionLock->Release(); DEBUG('t', "thread \"%s\" wait on the condition\n", currentThread->getName()); blockqueue->Append((void *)currentThread); // so go to sleep currentThread->Sleep(); conditionLock->Acquire(); (void) interrupt->SetLevel(oldLevel);}//-----------------------------------------------------------------------------void Condition::Signal(Lock* conditionLock) { Thread *thread; IntStatus oldLevel = interrupt->SetLevel(IntOff); thread = (Thread *)blockqueue->Remove(); if (thread != NULL) // make thread ready {DEBUG('t', "thread \"%s\" signal on the condition\n", currentThread->getName()); conditionLock->lockqueue->Append((void *)thread);} (void) interrupt->SetLevel(oldLevel);}//------------------------------------------------------------------------------void Condition::Broadcast(Lock* conditionLock) { Thread *thread; IntStatus oldLevel = interrupt->SetLevel(IntOff); while((thread = (Thread *)blockqueue->Remove())!=NULL) {DEBUG('t', "thread \"%s\" signal on the condition\n", currentThread->getName()); conditionLock->lockqueue->Append((void *)thread);} (void) interrupt->SetLevel(oldLevel);}//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -