package main

import (
	"fmt"
	"sync"
	"time"
)

// section: cond
var (
	ready bool
	mu    sync.Mutex
	cond  = sync.NewCond(&mu)
)

// worker waits for the ready signal before proceeding
func worker(id int, wg *sync.WaitGroup) {
	defer wg.Done()

	cond.L.Lock()
	// Wait until ready is true
	for !ready {
		fmt.Printf("Worker %d: Waiting for ready signal...\n", id)
		cond.Wait() // Releases lock, waits for signal, reacquires lock
	}
	fmt.Printf("Worker %d: Received signal, starting work!\n", id)
	cond.L.Unlock()

	// Simulate work
	time.Sleep(100 * time.Millisecond)
	fmt.Printf("Worker %d: Work completed\n", id)
}

// section: cond

// section: main
func main() {
	var wg sync.WaitGroup

	// Launch workers that will wait for signal
	for i := 1; i <= 5; i++ {
		wg.Add(1)
		go worker(i, &wg)
	}

	// Give workers time to start waiting
	time.Sleep(100 * time.Millisecond)

	fmt.Println("\nMain: Broadcasting ready signal...")
	cond.L.Lock()
	ready = true
	cond.Broadcast() // Wake up all waiting goroutines
	cond.L.Unlock()

	wg.Wait()
	fmt.Println("\nAll workers completed")
}

// section: main

// section: output
// Output:
// Worker 5: Waiting for ready signal...
// Worker 1: Waiting for ready signal...
// Worker 2: Waiting for ready signal...
// Worker 3: Waiting for ready signal...
// Worker 4: Waiting for ready signal...
//
// Main: Broadcasting ready signal...
// Worker 5: Received signal, starting work!
// Worker 1: Received signal, starting work!
// Worker 2: Received signal, starting work!
// Worker 3: Received signal, starting work!
// Worker 4: Received signal, starting work!
// Worker 1: Work completed
// Worker 2: Work completed
// Worker 3: Work completed
// Worker 4: Work completed
// Worker 5: Work completed
//
// All workers completed
// section: output
