Record shared read guards against a write probe and report the read status.

shared reads `sync.RWMutex.TryRLock` grants multiple read locks at once, so several readers can hold the lock together. A `TryLock` write probe is rejected while any read lock is held, so the report shows the write as blocked. The number of live read locks drives the coordination status from writable through single to shared.

RWMutex Read Coordination Report

readers
rwmutex_read_coordination_report.go
Replay: real traced execution (multi-file project)
package main

import (
	"fmt"
	"sync"
)

func main() {
	var readers = 2
	var lock sync.RWMutex
	active := 0
	for i := 0; i < readers; i++ {
		ok := lock.TryRLock()
		if ok {
			active++
		}
	}
	wok := lock.TryLock()
	writeBlocked := !wok
	var status string
	if active == 0 {
		status = "writable"
	} else if active == 1 {
		status = "single"
	} else {
		status = "shared"
	}
	fmt.Printf("readers=%d write_blocked=%t %s\n", active, writeBlocked, status)
}
package main

import (
	"fmt"
	"sync"
)

func main() {
	var readers = 0
	var lock sync.RWMutex
	active := 0
	for i := 0; i < readers; i++ {
		ok := lock.TryRLock()
		if ok {
			active++
		}
	}
	wok := lock.TryLock()
	writeBlocked := !wok
	var status string
	if active == 0 {
		status = "writable"
	} else if active == 1 {
		status = "single"
	} else {
		status = "shared"
	}
	fmt.Printf("readers=%d write_blocked=%t %s\n", active, writeBlocked, status)
}
package main

import (
	"fmt"
	"sync"
)

func main() {
	var readers = 1
	var lock sync.RWMutex
	active := 0
	for i := 0; i < readers; i++ {
		ok := lock.TryRLock()
		if ok {
			active++
		}
	}
	wok := lock.TryLock()
	writeBlocked := !wok
	var status string
	if active == 0 {
		status = "writable"
	} else if active == 1 {
		status = "single"
	} else {
		status = "shared"
	}
	fmt.Printf("readers=%d write_blocked=%t %s\n", active, writeBlocked, status)
}
  1. readers ← 2, lock ← sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:0}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}

    8func main() {9  var readers→ 2 = 2 //@readers=0, 110  var lock→ sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:0}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}} sync.RWMutex11  active→ 0 := 012  for i := 0; i < readers; i++ {
  2. lock ← sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:1}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}

    pass 1 of 2
    11active := 012for i0 := 0; i < readers2; i++ {13  ok→ true := lock→ sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:1}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}.TryRLock()14  if ok {
  3. active ← 1

    pass 1 of 2
    13ok := lock.TryRLock()14if oktrue {15  active→ 1++16}
  4. lock ← sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:2}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}

    pass 2 of 2
    11active := 012for i1 := 0; i < readers2; i++ {13  ok→ true := lock→ sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:2}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}.TryRLock()14  if ok {
  5. active ← 2

    pass 2 of 2
    13ok := lock.TryRLock()14if oktrue {15  active→ 2++16}
  6. wok ← false, writeBlocked ← true, status ← ""

    17}18wok→ false := locksync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:2}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}.TryLock()19writeBlocked→ true := !wokfalse20var status→ "" string21if active == 0 {
  7. status ← "shared"

    24  status = "single"25} else {26  status→ "shared" = "shared"27}
  8. fmt.Printf("readers=%d write_blocked=%t %s ", active, writeBlocked, st…

    27  }28  fmt.Printf("readers=%d write_blocked=%t %s\n", active2, writeBlockedtrue, status"shared")29}
    outputreaders=2 write_blocked=true shared
  1. readers ← 0, lock ← sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:0}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}

    8func main() {9  var readers→ 0 = 010  var lock→ sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:0}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}} sync.RWMutex11  active→ 0 := 012  for i := 0; i < readers; i++ {13    ok := lock.TryRLock()14    if ok {15      active++16    }17  }18  wok→ true := lock→ sync.RWMutex{w:sync.Mutex{state:1, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:-1073741824}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}.TryLock()19  writeBlocked→ false := !woktrue20  var status→ "" string21  if active == 0 {
  2. status ← "writable"

    20var status string21if active0 == 0 {22  status→ "writable" = "writable"23} else if active == 1 {
  3. fmt.Printf("readers=%d write_blocked=%t %s ", active, writeBlocked, st…

    27  }28  fmt.Printf("readers=%d write_blocked=%t %s\n", active0, writeBlockedfalse, status"writable")29}
    outputreaders=0 write_blocked=false writable
  1. readers ← 1, lock ← sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:0}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}

    8func main() {9  var readers→ 1 = 110  var lock→ sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:0}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}} sync.RWMutex11  active→ 0 := 012  for i := 0; i < readers; i++ {
  2. lock ← sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:1}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}

    11active := 012for i0 := 0; i < readers1; i++ {13  ok→ true := lock→ sync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:1}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}.TryRLock()14  if ok {
  3. active ← 1

    13ok := lock.TryRLock()14if oktrue {15  active→ 1++16}
  4. wok ← false, writeBlocked ← true, status ← ""

    17}18wok→ false := locksync.RWMutex{w:sync.Mutex{state:0, sema:0x0}, writerSem:0x0, readerSem:0x0, readerCount:atomic.Int32{_:atomic.noCopy{}, v:1}, readerWait:atomic.Int32{_:atomic.noCopy{}, v:0}}.TryLock()19writeBlocked→ true := !wokfalse20var status→ "" string21if active == 0 {
  5. status ← "single"

    22  status = "writable"23} else if active1 == 1 {24  status→ "single" = "single"25} else {
  6. fmt.Printf("readers=%d write_blocked=%t %s ", active, writeBlocked, st…

    27  }28  fmt.Printf("readers=%d write_blocked=%t %s\n", active1, writeBlockedtrue, status"single")29}
    outputreaders=1 write_blocked=true single