Start all the tasks in the group.
(ctx context.Context)
| 36 | |
| 37 | // Start all the tasks in the group. |
| 38 | func (g *Group) Start(ctx context.Context) { |
| 39 | // Lock access to the g.running and g.tasks map for the entirety of this function so that |
| 40 | // concurrent calls to Start() or Add(0) don't race. This ensures all tasks in this group |
| 41 | // are started based on a consistent snapshot of g.running and g.tasks. |
| 42 | g.mu.Lock() |
| 43 | defer g.mu.Unlock() |
| 44 | |
| 45 | ctx, g.cancel = context.WithCancel(ctx) |
| 46 | |
| 47 | if g.running == nil { |
| 48 | g.running = make(map[int]bool) |
| 49 | } |
| 50 | |
| 51 | for i := range g.tasks { |
| 52 | if g.running[i] { |
| 53 | continue |
| 54 | } |
| 55 | |
| 56 | g.running[i] = true |
| 57 | task := g.tasks[i] // Local variable for the closure below. |
| 58 | g.wg.Add(1) |
| 59 | |
| 60 | go func(i int) { |
| 61 | defer g.wg.Done() |
| 62 | |
| 63 | task.loop(ctx) |
| 64 | |
| 65 | // Ensure running map is updated before wait group Done() is called. |
| 66 | g.mu.Lock() |
| 67 | defer g.mu.Unlock() |
| 68 | |
| 69 | g.running[i] = false |
| 70 | }(i) |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | // Stop all tasks in the group. |
| 75 | // |