2

I am working on a school project (explains my restrictions in the question). My question is how to implement locks without semaphores in NACHOS. Although a NACHOS specific answer would be great, what I am looking for is a push in the right direction. So far, from my understanding, monitors use locks which use semaphores (mutexes really). Initially we thought to replace semaphores with monitors to implement locks, however, that didn't make sense.

Ameer Opat
  • 51
  • 1
  • 4

3 Answers3

0

Lock can be implemented by Thread:Sleep.

class Lock {
  public:
    Lock(char* debugName);          // initialize lock to be FREE
    ~Lock();                // deallocate lock
    char* getName() { return name; }    // debugging assist

    void Acquire(); // these are the only operations on a lock
    void Release(); // they are both *atomic*

    bool isHeldByCurrentThread() { return (thread == currentThread); }  // true if the current thread
                    // holds this lock.  Useful for
                    // checking in Release, and in
                    // Condition variable ops below.

  private:
    char* name;             // for debugging
    // plus some other stuff you'll need to define
    Thread *thread;     //the thread who holds this lock
    enum value {FREE, BUSY};
    List *queue;
};

Lock::Lock(char* debugName):name(debugName), thread(NULL), value(FREE), queue(new List())
{ }
Lock::~Lock()
{
    delete queue;
}
void Lock::Acquire()
{
    IntStatus oldLevel = interrupt->SetLevel(IntOff);   // disable interrupts
    if (value == BUSY) {
        queue->Append((void *)currentThread);
        currentThread->Sleep();
    }
    value = BUSY;
    thread = currentThread;
    (void) interrupt->SetLevel(oldLevel);   // re-enable interrupts
}
void Lock::Release()
{
    Thread *nextThread;
    IntStatus oldLevel = interrupt->SetLevel(IntOff);   // disable interrupts
    nextThread = (Thread *)queue->Remove();
    if (nextThread != NULL)    // make thread ready, consuming the V immediately
        scheduler->ReadyToRun(nextThread);
    value = FREE;
    (void) interrupt->SetLevel(oldLevel);   // re-enable interrupts
}
Liu Shuo
  • 11
  • 3
0

At first check whether the current holder of the lock is the current thread or not. Then use interrupt on-off and sleep to achieve lock. After a thread wakes from sleep, it should again check whether the lock is busy or free, because waking up a thread only passes it to the ready queue. Some other thread may meanwhile acquire the lock again before this thread can acquire the lock.

void Lock::Acquire() {
    ASSERT(!isHeldByCurrentThread());  // cannot acquire a lock twice

    IntStatus oldLevel = interrupt->SetLevel(IntOff);   // disable interrupts
    while (freeOrBusy == 'b') {
        queue->Append((void *)currentThread);
        currentThread->Sleep();
    }
    freeOrBusy = 'b';
    currentHolder = currentThread;
    (void) interrupt->SetLevel(oldLevel);   // re-enable interrupts
}

void Lock::Release() {
    ASSERT(isHeldByCurrentThread());

    IntStatus oldLevel = interrupt->SetLevel(IntOff);
    freeOrBusy = 'f';
    currentHolder = NULL;

    Thread *thread = (Thread *)queue->Remove();   // "queue" is the list of threads waiting
    if (thread != NULL)    // make thread ready
       scheduler->ReadyToRun(thread);  

    (void) interrupt->SetLevel(oldLevel);

}
Preetom Saha Arko
  • 2,588
  • 4
  • 21
  • 37
0

You might want to think about spin-locks which do busy-waiting and do not require semaphore.However in a uniprocessor spin-locks are not used.

vjain27
  • 3,514
  • 9
  • 41
  • 60