РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
849 of 1593 menu

sync.Cond

Тип sync.Cond представляет условную переменную, которая используется для синхронизации горутин. Она позволяет одной или нескольким горутинам ожидать наступления определенного условия, а другой горутине - сигнализировать о том, что условие выполнено. sync.Cond создается с помощью функции sync.NewCond, которая принимает в качестве аргумента блокировку (обычно sync.Mutex или sync.RWMutex). Основные методы: Wait - ожидает сигнала, Signal - пробуждает одну ожидающую горутину, Broadcast - пробуждает все ожидающие горутины.

Создание sync.Cond

Для создания условной переменной используется функция sync.NewCond, которая принимает в качестве аргумента блокировку, реализующую интерфейс sync.Locker. Обычно это sync.Mutex или sync.RWMutex.

package main import ( "fmt" "sync" "time" ) func main() { var mutex sync.Mutex cond := sync.NewCond(&mutex) go func() { time.Sleep(1 * time.Second) cond.Signal() }() cond.L.Lock() cond.Wait() fmt.Println("Получен сигнал") cond.L.Unlock() }

Результат выполнения кода:

"Получен сигнал"

Метод Wait - ожидание сигнала

Метод Wait атомарно разблокирует блокировку и переводит горутину в состояние ожидания. Когда другая горутина вызывает Signal или Broadcast, Wait пробуждается, снова захватывает блокировку и продолжает выполнение. Перед вызовом Wait блокировка должна быть захвачена.

package main import ( "fmt" "sync" "time" ) func main() { var mutex sync.Mutex cond := sync.NewCond(&mutex) var ready bool go func() { time.Sleep(2 * time.Second) cond.L.Lock() ready = true cond.L.Unlock() cond.Signal() }() cond.L.Lock() for !ready { cond.Wait() } fmt.Println("Горутина готова") cond.L.Unlock() }

Результат выполнения кода:

"Горутина готова"

Метод Signal - пробуждение одной горутины

Метод Signal пробуждает одну горутину, ожидающую на условной переменной. Если ожидающих горутин нет, вызов Signal не производит никакого эффекта. Этот метод обычно вызывается после изменения общего состояния, чтобы уведомить одну из ожидающих горутин о том, что условие могло измениться.

package main import ( "fmt" "sync" "time" ) func main() { var mutex sync.Mutex cond := sync.NewCond(&mutex) counter := 0 for i := 0; i < 3; i++ { go func(id int) { cond.L.Lock() for counter < 1 { cond.Wait() } fmt.Printf("Горутина %d пробуждена\n", id) cond.L.Unlock() }(i) } time.Sleep(1 * time.Second) cond.L.Lock() counter = 1 cond.L.Unlock() cond.Signal() time.Sleep(1 * time.Second) }

Результат выполнения кода:

"Горутина 2 пробуждена"

Метод Broadcast - пробуждение всех горутин

Метод Broadcast пробуждает все горутины, ожидающие на условной переменной. Этот метод используется, когда условие изменилось таким образом, что может стать актуальным для всех ожидающих горутин. Как и Signal, его следует вызывать после захвата блокировки.

package main import ( "fmt" "sync" "time" ) func main() { var mutex sync.Mutex cond := sync.NewCond(&mutex) counter := 0 for i := 0; i < 3; i++ { go func(id int) { cond.L.Lock() for counter < 2 { cond.Wait() } fmt.Printf("Горутина %d пробуждена\n", id) cond.L.Unlock() }(i) } time.Sleep(1 * time.Second) cond.L.Lock() counter = 2 cond.L.Unlock() cond.Broadcast() time.Sleep(1 * time.Second) }

Результат выполнения кода:

"Горутина 2 пробуждена" "Горутина 1 пробуждена" "Горутина 0 пробуждена"

Пример с несколькими условиями

В реальных сценариях sync.Cond часто используется с несколькими условиями. Важно всегда проверять условие в цикле, так как горутина может быть пробуждена по ложному сигналу или до того, как условие действительно выполнится.

package main import ( "fmt" "sync" "time" ) func main() { var mutex sync.Mutex cond := sync.NewCond(&mutex) queue := make([]int, 0) maxSize := 3 go func() { for i := 0; i < 10; i++ { cond.L.Lock() for len(queue) >= maxSize { cond.Wait() } queue = append(queue, i) fmt.Printf("Добавлен элемент: %d, очередь: %v\n", i, queue) cond.L.Unlock() cond.Signal() time.Sleep(200 * time.Millisecond) } }() go func() { for i := 0; i < 10; i++ { time.Sleep(300 * time.Millisecond) cond.L.Lock() for len(queue) == 0 { cond.Wait() } val := queue[0] queue = queue[1:] fmt.Printf("Извлечен элемент: %d, очередь: %v\n", val, queue) cond.L.Unlock() cond.Signal() } }() time.Sleep(5 * time.Second) }

Результат выполнения кода:

"Добавлен элемент: 0, очередь: [0]" "Добавлен элемент: 1, очередь: [0 1]" "Добавлен элемент: 2, очередь: [0 1 2]" "Извлечен элемент: 0, очередь: [1 2]" "Добавлен элемент: 3, очередь: [1 2 3]" "Извлечен элемент: 1, очередь: [2 3]" "Добавлен элемент: 4, очередь: [2 3 4]"

Смотрите также

  • функцию sync.NewCond,
    которая создает новую условную переменную
  • метод sync.Cond.Wait,
    который ожидает сигнала на условной переменной
  • метод sync.Cond.Signal,
    который пробуждает одну ожидающую горутину
  • метод sync.Cond.Broadcast,
    который пробуждает все ожидающие горутины
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить