package main import ( "context" "fmt" "time" ) // worker simulates an operation that needs to be cancelable. func worker(ctx context.Context, id int, dataCh <-chan string) { fmt.Printf("Worker %d: Starting ", id) for { select { case <-ctx.Done(): fmt.Printf("Worker %d: Context cancelled. Shutting down. ", id) return case data, ok := <-dataCh: if !ok { fmt.Printf("Worker %d: Data channel closed. Shutting down. ", id) return } fmt.Printf("Worker %d: Processing data: %s ", id, data) // Simulate some work time.Sleep(500 * time.Millisecond) } } } func main() { // Create a context that can be cancelled. ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Ensure cancellation if main exits early dataChannel := make(chan string) // Start a few workers go worker(ctx, 1, dataChannel) go worker(ctx, 2, dataChannel) // Simulate sending some data go func() { for i := 0; i < 5; i++ { select { case <-ctx.Done(): fmt.Println("Producer: Context cancelled. Stopping data generation.") return case dataChannel <- fmt.Sprintf("message-%d", i): fmt.Printf("Producer: Sent message-%d ", i) } time.Sleep(200 * time.Millisecond) } // Close the channel when done sending data close(dataChannel) fmt.Println("Producer: Data channel closed.") }() // Let the workers run for a bit time.Sleep(2 * time.Second) fmt.Println("Main: Sending cancellation signal...") cancel() // Cancel the context // Give workers time to shut down time.Sleep(1 * time.Second) fmt.Println("Main: Exiting.") }