A notable example in the experimental package that uses context is one we've already looked at – semaphore. Now that we have a better understanding of what context is for, it should be pretty obvious why the acquire operation also takes a context in as an argument.
When creating our application, we can provide a context with a timeout or cancellation and act accordingly:
func main() {
s := semaphore.NewWeighted(int64(5))
ctx, canc := context.WithTimeout(context.Background(), time.Second)
defer canc()
wg := sync.WaitGroup{}
wg.Add(20)
for i := 0; i < 20; i++ {
go func(i int) {
defer wg.Done()
if err := s.Acquire(ctx, 1); err != nil {
fmt.Println(i, err)
return
}
go func(i int) {
fmt.Println(i)
time.Sleep(time.Second / 2)
s.Release(1)
}(i)
}(i)
}
wg.Wait()
}
Running this application will show that the semaphore is acquired for the first second, but after that the context expires and all the remaining operations fail.