liveBook · Manning

Starvation

As explained in Learn Concurrent Programming with Go

Starvation is a situation in which an execution is blocked from gaining access to a shared resource because other executions keep it unavailable for a long time or indefinitely.

Starvation occurs when one execution cannot access a shared resource because other executions keep it unavailable for a long time or indefinitely. In a read-preferring readers–writer lock, continuously arriving readers can prevent a waiting writer from ever acquiring the write lock. section 5.1.4

Readers block the writer indefinitely

Two reader goroutines repeatedly acquire a read lock, sleep for one second while holding it, print “Read done,” and release the lock. The main goroutine later requests the write lock, but the readers repeatedly overlap or alternate, so “Write finished” never appears and the output continues indefinitely. section 5.1.4

A practical remedy is a write-preferring readers–writer mutex. When a writer begins waiting, new readers wait too. The lock tracks active readers, waiting writers, and whether a writer is active; condition-variable broadcasts wake suspended executions when access may proceed. section 5.1.4 section 5.4

The write-preferring design coordinates access as follows:

  • Readers wait while a writer is active or any writer is waiting, then increment the active-reader count. section 5.1.4
  • Writers increment the waiting count and wait until no readers or active writer remain, then mark themselves active. section 5.1.4
  • The last reader broadcasts to waiting executions, and a writer broadcasts after releasing the write lock. section 5.1.4
Figure 5.8 The writer goroutine is unable to access the resource indefinitely due to readers hogging resource access.

Visualizes readers continuously holding access while the writer remains unable to enter the shared resource. section 5.1.4

Listing 5.11 Write-preferring readers–writer mutex type
package main

import (
    "sync"
)

type ReadWriteMutex struct {
    readersCounter int                                         #1
    writersWaiting int                                         #2
    writerActive   bool                                        #3
    cond           *sync.Cond
}


func NewReadWriteMutex() *ReadWriteMutex {
    return &ReadWriteMutex{cond: sync.NewCond(&sync.Mutex{})}  #4
}
#1 Stores the number of readers currently holding the read lock
#2 Stores the number of writers currently waiting
#3 Indicates if a writer is holding the write lock
#4 Initializes a new ReadWriteMutex with a new condition variable and associated mutex

Shows the state carried by a write-preferring readers–writer mutex: reader count, waiting writers, active writer, and condition variable. section 5.1.4

How Learn Concurrent Programming with Go covers it

How deep it goes
Explains the failure sequence and implements lock-state checks, condition waits, counters, and broadcasts.
Examples
Uses two looping Go readers, a waiting writer, indefinite output, and a write-preferring lock that prints “Write finished.”
What it assumes
Assumes mutex-based readers–writer locks while teaching condition-variable waiting and signaling as the corrective mechanism.
What you can do after
Build it from scratch using condition variables and mutexes to prevent write starvation in a readers–writer lock.
How it connects
Connects starvation with readers–writer locks, mutexes, condition variables, and semaphores.

Also explained in

Compare how 4 books explain starvation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Concurrent Programming with Go. The section links point to the parts of the book it draws on.