codekingpro/portable-devtools
114k
1// Copyright 2016 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package context_test6 7import (8 "context"9 "errors"10 "fmt"11 "net"12 "sync"13 "time"14)15 16var neverReady = make(chan struct{}) // never closed17 18// This example demonstrates the use of a cancelable context to prevent a19// goroutine leak. By the end of the example function, the goroutine started20// by gen will return without leaking.21func ExampleWithCancel() {22 // gen generates integers in a separate goroutine and23 // sends them to the returned channel.24 // The callers of gen need to cancel the context once25 // they are done consuming generated integers not to leak26 // the internal goroutine started by gen.27 gen := func(ctx context.Context) <-chan int {28 dst := make(chan int)29 n := 130 go func() {31 for {32 select {33 case <-ctx.Done():34 return // returning not to leak the goroutine35 case dst <- n:36 n++37 }38 }39 }()40 return dst41 }42 43 ctx, cancel := context.WithCancel(context.Background())44 defer cancel() // cancel when we are finished consuming integers45 46 for n := range gen(ctx) {47 fmt.Println(n)48 if n == 5 {49 break50 }51 }52 // Output:53 // 154 // 255 // 356 // 457 // 558}59 60// This example passes a context with an arbitrary deadline to tell a blocking61// 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 its67 // cancellation function in any case. Failure to do so may keep the68 // 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 exceeded80}81 82// This example passes a context with a timeout to tell a blocking function that83// it should abandon its work after the timeout elapses.84func ExampleWithTimeout() {85 // Pass a context with a timeout to tell a blocking function that it86 // 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 exceeded99}100 101// This example demonstrates how a value can be passed to the context102// and also how to retrieve it if it exists.103func ExampleWithValue() {104 type favContextKey string105 106 f := func(ctx context.Context, k favContextKey) {107 if v := ctx.Value(k); v != nil {108 fmt.Println("found value:", v)109 return110 }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: Go122 // key not found: color123}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 Broadcast131 // below won't occur before the call to Wait, which would result132 // 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 goroutines142 // 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 to149 // Wait may unblock due to some other goroutine's context being canceled,150 // so to be sure that ctx is actually canceled 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 nil159 }160 161 cond := sync.NewCond(new(sync.Mutex))162 163 var wg sync.WaitGroup164 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 exceeded183 // context deadline exceeded184 // context deadline exceeded185 // context deadline exceeded186}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 <-stopc202 conn.SetReadDeadline(time.Time{})203 return n, ctx.Err()204 }205 return n, err206 }207 208 listener, err := net.Listen("tcp", "localhost:0")209 if err != nil {210 fmt.Println(err)211 return212 }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 return219 }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 exceeded231}232 233// This example uses AfterFunc to define a function which combines234// 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 canceled263}264 