1 | // vtest flaky: true |
2 | // vtest retry: 3 |
3 | import context |
4 | |
5 | // This example demonstrates the use of a cancelable context to prevent a |
6 | // routine leak. By the end of the example function, the routine started |
7 | // by gen will return without leaking. |
8 | fn test_with_cancel() { |
9 | // gen generates integers in a separate routine and |
10 | // sends them to the returned channel. |
11 | // The callers of gen need to cancel the context once |
12 | // they are done consuming generated integers not to leak |
13 | // the internal routine started by gen. |
14 | gen := fn (mut ctx context.Context) chan int { |
15 | dst := chan int{} |
16 | spawn fn (mut ctx context.Context, dst chan int) { |
17 | mut v := 0 |
18 | ch := ctx.done() |
19 | for { |
20 | select { |
21 | _ := <-ch { |
22 | // returning not to leak the routine |
23 | return |
24 | } |
25 | dst <- v { |
26 | v++ |
27 | } |
28 | } |
29 | } |
30 | }(mut ctx, dst) |
31 | return dst |
32 | } |
33 | |
34 | mut background := context.background() |
35 | mut ctx, cancel := context.with_cancel(mut background) |
36 | defer { |
37 | cancel() |
38 | } |
39 | |
40 | mut mut_ctx := ctx |
41 | mut ctx2 := &mut_ctx |
42 | ch := gen(mut ctx2) |
43 | for i in 0 .. 5 { |
44 | v := <-ch |
45 | assert i == v |
46 | } |
47 | } |