Skip to main content

Overview

The LibraryMonitor class implements a monitor for the classic readers-writer problem. It allows multiple readers to access the library simultaneously, but writers (the librarian updating the catalog) require exclusive access. The monitor implements a writer-priority policy to prevent writer starvation.

Constructor

LibraryMonitor
class
Creates a new library monitor with no active readers or writers.
const monitor = new LibraryMonitor();
Initial State:
  • activeReaders: 0
  • writerActive: false
  • readerQueue: []
  • writerQueue: []
  • readerGranted: new Set()
  • writerGranted: null

Properties

activeReaders
number
Count of readers currently inside the library.
writerActive
boolean
true when the librarian is actively updating the catalog (writing).
readerQueue
Array<Thread>
FIFO queue of reader threads blocked and waiting to enter.
writerQueue
Array<Thread>
FIFO queue of writer threads blocked and waiting to enter.
readerGranted
Set<Thread>
Set of readers that have been granted permission to enter but haven’t entered yet.
writerGranted
Thread | null
The writer thread that has been granted permission to enter, or null if none.

Methods

enterRead(thread)

Reader thread requests entry to the library.
thread
Thread
required
The reader thread attempting to enter.
return
boolean
  • true: Reader successfully entered the library
  • false: Reader is blocked and added to the queue
Behavior:
  1. Already granted: If thread was previously granted permission, consumes permission and increments activeReaders
  2. Can enter: If no writer is active and no writers are waiting (writer priority), allows entry
  3. Must wait: Blocks thread if writer is active or writers are waiting
Source: monitorLibrary.js:19
// Example: Reader entering library
const entered = monitor.enterRead(readerThread);
if (entered) {
  console.log('Reader entered library');
  // Read from catalog
} else {
  console.log('Reader blocked, waiting for writer to finish');
}

exitRead()

Reader thread exits the library.
return
Array<Thread>
List of threads awakened by this exit (if this was the last reader).
Behavior:
  • Decrements activeReaders count
  • Calls wakeUpThreads() to potentially wake waiting writers or readers
  • If this was the last reader and a writer is waiting, the writer may be awakened
Source: monitorLibrary.js:41
// Example: Reader exiting
const awakened = monitor.exitRead();
if (awakened.length > 0) {
  console.log(`Woke up ${awakened.length} threads`);
}

enterWrite(thread)

Writer thread requests exclusive access to update the catalog.
thread
Thread
required
The writer thread attempting to enter.
return
boolean
  • true: Writer successfully entered (has exclusive access)
  • false: Writer is blocked and added to the queue
Behavior:
  1. Already granted: If thread was previously granted permission, consumes permission and sets writerActive
  2. Can enter: If no writer is active and no readers are present, allows entry
  3. Must wait: Blocks thread if any readers are present or another writer is active
Source: monitorLibrary.js:47
// Example: Writer entering library
const entered = monitor.enterWrite(writerThread);
if (entered) {
  console.log('Writer has exclusive access');
  // Update catalog
} else {
  console.log('Writer blocked, waiting for readers to exit');
}

exitWrite()

Writer thread exits the library, releasing exclusive access.
return
Array<Thread>
List of threads awakened (either one writer or all waiting readers).
Behavior:
  • Sets writerActive to false
  • Calls wakeUpThreads() to wake next writer or all waiting readers
Source: monitorLibrary.js:67
// Example: Writer exiting
const awakened = monitor.exitWrite();
console.log(`Writer exited, woke up ${awakened.length} threads`);

wakeUpThreads()

Internal method implementing the monitor’s wake-up policy.
return
Array<Thread>
List of threads that were awakened and granted permission.
Writer-Priority Policy:
  1. If a writer is waiting and the library is empty (no active writer, no active readers), wake one writer
  2. Otherwise, if readers are waiting and no writer is waiting/active, wake all readers
Source: monitorLibrary.js:73
// Internal wake-up logic
if (canWakeWriter) {
  const writer = writerQueue.shift();
  writer.state = 'ready';
  writerGranted = writer;
  return [writer];
}

if (canWakeReaders) {
  const readers = [];
  while (readerQueue.length > 0) {
    const reader = readerQueue.shift();
    reader.state = 'ready';
    readerGranted.add(reader);
    readers.push(reader);
  }
  return readers;
}

Usage Example

import { LibraryMonitor } from './core/monitorLibrary.js';

const library = new LibraryMonitor();

// Reader thread
function readerCode(thread) {
  const entered = library.enterRead(thread);
  
  if (entered) {
    console.log(`${thread.name} reading catalog`);
    
    // Read for some time
    setTimeout(() => {
      const awakened = library.exitRead();
      console.log(`${thread.name} finished reading`);
    }, 1000);
  }
}

// Writer thread (librarian)
function writerCode(thread) {
  const entered = library.enterWrite(thread);
  
  if (entered) {
    console.log(`${thread.name} updating catalog (exclusive)`);
    
    // Update catalog
    setTimeout(() => {
      const awakened = library.exitWrite();
      console.log(`${thread.name} finished updating`);
    }, 2000);
  }
}

Writer-Priority Policy

The monitor implements writer priority to prevent writer starvation:
// Readers block if writer is waiting
const writerWaiting = this.writerQueue.length > 0;
if (!this.writerActive && !writerWaiting) {
  // Only allow reader if no writers waiting
  this.activeReaders += 1;
  return true;
}
This ensures:
  • Writers don’t starve when many readers arrive continuously
  • Once a writer arrives, new readers must wait
  • Existing readers finish, then writer gets exclusive access

Grant Mechanism

The monitor uses a grant-based approach:
  1. Wake-up phase: wakeUpThreads() marks threads as “granted” permission
  2. Entry phase: enterRead()/enterWrite() checks for granted permission
  3. Consume grant: Thread consumes its permission and enters
This two-phase approach prevents race conditions where a thread is awakened but can’t immediately verify entry conditions.
// Wake-up grants permission
this.readerGranted.add(reader);
reader.state = 'ready';

// Later, when thread runs enterRead again
if (this.readerGranted.has(thread)) {
  this.readerGranted.delete(thread); // Consume grant
  this.activeReaders += 1;
  return true;
}

Concurrent Readers

Multiple readers can be in the library simultaneously:
// Scenario:
monitor.enterRead(reader1); // activeReaders = 1
monitor.enterRead(reader2); // activeReaders = 2
monitor.enterRead(reader3); // activeReaders = 3

// All three readers have concurrent access

monitor.enterWrite(writer1); // BLOCKED - readers present

monitor.exitRead(); // activeReaders = 2, writer still blocked
monitor.exitRead(); // activeReaders = 1, writer still blocked
monitor.exitRead(); // activeReaders = 0, writer awakened!

Exclusive Writer

Writers require complete isolation:
monitor.enterWrite(writer1); // Exclusive access

monitor.enterRead(reader1);  // BLOCKED
monitor.enterRead(reader2);  // BLOCKED
monitor.enterWrite(writer2); // BLOCKED

monitor.exitWrite(); // Wakes next writer OR all readers