Внедрить замки без семафоров - PullRequest
2 голосов
/ 09 февраля 2012

Я работаю над школьным проектом (объясняет мои ограничения в вопросе).У меня вопрос, как реализовать блокировки без семафоров в NACHOS.Хотя конкретный ответ NACHOS был бы великолепен, я ищу толчок в правильном направлении.Пока, насколько я понимаю, мониторы используют блокировки, которые используют семафоры (действительно мьютексы).Первоначально мы думали заменить семафоры мониторами для реализации блокировок, однако это не имело смысла.

Ответы [ 3 ]

0 голосов
/ 08 декабря 2012

Блокировка может быть реализована с помощью 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
}
0 голосов
/ 22 апреля 2017

Сначала проверьте, является ли текущий держатель замка текущим потоком или нет.Затем используйте прерывание вкл-выкл и спать, чтобы добиться блокировки.После того, как поток выходит из спящего режима, он должен снова проверить, занята ли блокировка или свободна, потому что пробуждение потока только передает его в готовую очередь.Тем временем другой поток может снова получить блокировку, прежде чем этот поток сможет получить блокировку.

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);

}
0 голосов
/ 16 февраля 2012

Возможно, вы захотите подумать о спин-блокировках, которые делают ожидание занято и не требуют семафора. Однако в однопроцессорной спин-блокировке не используются.

...