1// Copyright 2016 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package context_test 6 7import ( 8 "context" 9 "errors" 10 "fmt" 11 "net" 12 "sync" 13 "time" 14) 15 16var neverReady = make(chan struct{}) // never closed 17 18// This example demonstrates the use of a cancelable context to prevent a 19// goroutine leak. By the end of the example function, the goroutine started 20// by gen will return without leaking. 21func ExampleWithCancel() { 22 // gen generates integers in a separate goroutine and 23 // sends them to the returned channel. 24 // The callers of gen need to cancel the context once 25 // they are done consuming generated integers not to leak 26 // the internal goroutine started by gen. 27 gen := func(ctx context.Context) <-chan int { 28 dst := make(chan int) 29 n := 1 30 go func() { 31 for { 32 select { 33 case <-ctx.Done(): 34 return // returning not to leak the goroutine 35 case dst <- n: 36 n++ 37 } 38 } 39 }() 40 return dst 41 } 42 43 ctx, cancel := context.WithCancel(context.Background()) 44 defer cancel() // cancel when we are finished consuming integers 45 46 for n := range gen(ctx) { 47 fmt.Println(n) 48 if n == 5 { 49 break 50 } 51 } 52 // Output: 53 // 1 54 // 2 55 // 3 56 // 4 57 // 5 58} 59 60// This example passes a context with an arbitrary deadline to tell a blocking 61// function that it should abandon its work as soon as it gets to it. 62func ExampleWithDeadline() { 63 d := time.Now().Add(shortDuration) 64 ctx, cancel := context.WithDeadline(context.Background(), d) 65 66 // Even though ctx will be expired, it is good practice to call its 67 // cancellation function in any case. Failure to do so may keep the 68 // context and its parent alive longer than necessary. 69 defer cancel() 70 71 select { 72 case <-neverReady: 73 fmt.Println("ready") 74 case <-ctx.Done(): 75 fmt.Println(ctx.Err()) 76 } 77 78 // Output: 79 // context deadline exceeded 80} 81 82// This example passes a context with a timeout to tell a blocking function that 83// it should abandon its work after the timeout elapses. 84func ExampleWithTimeout() { 85 // Pass a context with a timeout to tell a blocking function that it 86 // should abandon its work after the timeout elapses. 87 ctx, cancel := context.WithTimeout(context.Background(), shortDuration) 88 defer cancel() 89 90 select { 91 case <-neverReady: 92 fmt.Println("ready") 93 case <-ctx.Done(): 94 fmt.Println(ctx.Err()) // prints "context deadline exceeded" 95 } 96 97 // Output: 98 // context deadline exceeded 99} 100 101// This example demonstrates how a value can be passed to the context 102// and also how to retrieve it if it exists. 103func ExampleWithValue() { 104 type favContextKey string 105 106 f := func(ctx context.Context, k favContextKey) { 107 if v := ctx.Value(k); v != nil { 108 fmt.Println("found value:", v) 109 return 110 } 111 fmt.Println("key not found:", k) 112 } 113 114 k := favContextKey("language") 115 ctx := context.WithValue(context.Background(), k, "Go") 116 117 f(ctx, k) 118 f(ctx, favContextKey("color")) 119 120 // Output: 121 // found value: Go 122 // key not found: color 123} 124 125// This example uses AfterFunc to define a function which waits on a sync.Cond, 126// stopping the wait when a context is canceled. 127func ExampleAfterFunc_cond() { 128 waitOnCond := func(ctx context.Context, cond *sync.Cond, conditionMet func() bool) error { 129 stopf := context.AfterFunc(ctx, func() { 130 // We need to acquire cond.L here to be sure that the Broadcast 131 // below won't occur before the call to Wait, which would result 132 // in a missed signal (and deadlock). 133 cond.L.Lock() 134 defer cond.L.Unlock() 135 136 // If multiple goroutines are waiting on cond simultaneously, 137 // we need to make sure we wake up exactly this one. 138 // That means that we need to Broadcast to all of the goroutines, 139 // which will wake them all up. 140 // 141 // If there are N concurrent calls to waitOnCond, each of the goroutines 142 // will spuriously wake up O(N) other goroutines that aren't ready yet, 143 // so this will cause the overall CPU cost to be O(N²). 144 cond.Broadcast() 145 }) 146 defer stopf() 147 148 // Since the wakeups are using Broadcast instead of Signal, this call to 149 // Wait may unblock due to some other goroutine's context becoming done, 150 // so to be sure that ctx is actually done we need to check it in a loop. 151 for !conditionMet() { 152 cond.Wait() 153 if ctx.Err() != nil { 154 return ctx.Err() 155 } 156 } 157 158 return nil 159 } 160 161 cond := sync.NewCond(new(sync.Mutex)) 162 163 var wg sync.WaitGroup 164 for i := 0; i < 4; i++ { 165 wg.Add(1) 166 go func() { 167 defer wg.Done() 168 169 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond) 170 defer cancel() 171 172 cond.L.Lock() 173 defer cond.L.Unlock() 174 175 err := waitOnCond(ctx, cond, func() bool { return false }) 176 fmt.Println(err) 177 }() 178 } 179 wg.Wait() 180 181 // Output: 182 // context deadline exceeded 183 // context deadline exceeded 184 // context deadline exceeded 185 // context deadline exceeded 186} 187 188// This example uses AfterFunc to define a function which reads from a net.Conn, 189// stopping the read when a context is canceled. 190func ExampleAfterFunc_connection() { 191 readFromConn := func(ctx context.Context, conn net.Conn, b []byte) (n int, err error) { 192 stopc := make(chan struct{}) 193 stop := context.AfterFunc(ctx, func() { 194 conn.SetReadDeadline(time.Now()) 195 close(stopc) 196 }) 197 n, err = conn.Read(b) 198 if !stop() { 199 // The AfterFunc was started. 200 // Wait for it to complete, and reset the Conn's deadline. 201 <-stopc 202 conn.SetReadDeadline(time.Time{}) 203 return n, ctx.Err() 204 } 205 return n, err 206 } 207 208 listener, err := net.Listen("tcp", ":0") 209 if err != nil { 210 fmt.Println(err) 211 return 212 } 213 defer listener.Close() 214 215 conn, err := net.Dial(listener.Addr().Network(), listener.Addr().String()) 216 if err != nil { 217 fmt.Println(err) 218 return 219 } 220 defer conn.Close() 221 222 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond) 223 defer cancel() 224 225 b := make([]byte, 1024) 226 _, err = readFromConn(ctx, conn, b) 227 fmt.Println(err) 228 229 // Output: 230 // context deadline exceeded 231} 232 233// This example uses AfterFunc to define a function which combines 234// the cancellation signals of two Contexts. 235func ExampleAfterFunc_merge() { 236 // mergeCancel returns a context that contains the values of ctx, 237 // and which is canceled when either ctx or cancelCtx is canceled. 238 mergeCancel := func(ctx, cancelCtx context.Context) (context.Context, context.CancelFunc) { 239 ctx, cancel := context.WithCancelCause(ctx) 240 stop := context.AfterFunc(cancelCtx, func() { 241 cancel(context.Cause(cancelCtx)) 242 }) 243 return ctx, func() { 244 stop() 245 cancel(context.Canceled) 246 } 247 } 248 249 ctx1, cancel1 := context.WithCancelCause(context.Background()) 250 defer cancel1(errors.New("ctx1 canceled")) 251 252 ctx2, cancel2 := context.WithCancelCause(context.Background()) 253 254 mergedCtx, mergedCancel := mergeCancel(ctx1, ctx2) 255 defer mergedCancel() 256 257 cancel2(errors.New("ctx2 canceled")) 258 <-mergedCtx.Done() 259 fmt.Println(context.Cause(mergedCtx)) 260 261 // Output: 262 // ctx2 canceled 263} 264