cpp

Ожидание завершения всех потоков

Как уже говорилось, потоки автоматически завершают работу при выходе потока управления из функции main(), поэтому важно дождаться окончания выполнения потоков. В предыдущих примерах для этого мы использовали функции Sleep() и Scanln(). Однако трудно назвать эти способы универсальными. Какое время указать внутри функции Sleep(), чтобы потоки успели полностью выполниться и при этом пользователю не пришлось ждать, если потоки завершились раньше этого времени? Угадать это значение невозможно. Одним из способов решения проблемы является использование структуры WaitGroup из пакета sync.

Структура WaitGroup содержит следующие методы:

  • Add() — добавляет указанное количество потоков к существующему значению счетчика. Значение может быть отрицательным. Если счетчик будет иметь отрицательное значение, то генерируется паника. Формат метода:
(*sync.WaitGroup).Add(delta int)
  • Done() — уменьшает значение счетчика на единицу. Этот метод следует вызывать при завершении потока. Формат метода:
(*sync.WaitGroup).Done()
  • Wait() — блокирует выполнение потока до тех пор, пока значение счетчика не станет равно нулю. Формат метода:
(*sync.WaitGroup).Wait()
Обратите внимание

Пример использования структуры WaitGroup приведен в листинге 18.3.

Листинг 18.3. Ожидание завершения всех потоков

package main

import (
   "fmt"
   "sync"
   "time"
)

func main() {
   fmt.Println("Начало функции main()")
   var wg sync.WaitGroup
   for i := 1; i < 4; i++ {
      wg.Add(1)          // Увеличиваем счетчик потоков на единицу
      go func(n int) {
         defer wg.Done() // Уменьшаем счетчик потоков на единицу
         for j := 1; j < 11; j++ {
            fmt.Println("Поток:", n, "j =", j)
            time.Sleep(time.Second) // Имитация выполнения задачи
         }
      }(i)
   }
   wg.Wait() // Ожидаем завершения всех потоков
   fmt.Println("Конец функции main()")
}

Учебник Go (Golang)
Учебник Go (Golang) в формате PDF