package main

import (
	"context"
	"fmt"
	"sync"
)

// Start owns the goroutine and returns a join signal for its caller.
func Start(ctx context.Context, jobs <-chan int, visit func(int)) <-chan struct{} {
	done := make(chan struct{})
	go func() {
		defer close(done)
		for {
			select {
			case <-ctx.Done():
				return
			case n, ok := <-jobs:
				if !ok {
					return
				}
				visit(n) // This callback must finish; cancellation cannot interrupt it.
			}
		}
	}()
	return done
}

func SendResult(ctx context.Context, results chan<- int, value int) {
	select {
	case results <- value:
	case <-ctx.Done():
		return
	}
}
func main() {
	ctx, cancel := context.WithCancel(context.Background())
	jobs := make(chan int)
	var mu sync.Mutex
	total := 0
	done := Start(ctx, jobs, func(n int) { mu.Lock(); total += n; mu.Unlock() })
	jobs <- 7
	cancel()
	<-done
	mu.Lock()
	fmt.Println("joined; total:", total)
	mu.Unlock()
}
