sync.Cond.Signal
Метод sync.Cond.Signal пробуждает одну из горутин, ожидающих на условной переменной.
Выбор пробуждаемой горутины произволен и зависит от планировщика Go.
Если ни одна горутина не ожидает сигнала, метод ничего не делает.
Метод должен вызываться при удержании блокировки sync.Cond.L,
хотя технически это не обязательно, но рекомендуется для корректной работы.
Синтаксис
c.Signal()
Пример с одной ожидающей горутиной
Рассмотрим базовый пример, где одна горутина ожидает сигнала, а другая отправляет его:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
go func() {
mu.Lock()
defer mu.Unlock()
fmt.Println("Горутина ожидает сигнала")
cond.Wait()
fmt.Println("Горутина получила сигнал")
}()
time.Sleep(100 * time.Millisecond)
mu.Lock()
fmt.Println("Отправляем сигнал")
cond.Signal()
mu.Unlock()
time.Sleep(100 * time.Millisecond)
}
Результат выполнения кода:
"Горутина ожидает сигнала"
"Отправляем сигнал"
"Горутина получила сигнал"
Пример с несколькими ожидающими горутинами
Покажем, что метод Signal пробуждает только одну горутину из нескольких ожидающих:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
mu.Lock()
defer mu.Unlock()
fmt.Printf("Горутина %d ожидает\n", id)
cond.Wait()
fmt.Printf("Горутина %d проснулась\n", id)
}(i)
}
time.Sleep(100 * time.Millisecond)
mu.Lock()
fmt.Println("Отправляем один сигнал")
cond.Signal()
mu.Unlock()
time.Sleep(100 * time.Millisecond)
mu.Lock()
fmt.Println("Отправляем второй сигнал")
cond.Signal()
mu.Unlock()
wg.Wait()
}
Результат выполнения кода:
"Горутина 3 ожидает"
"Горутина 1 ожидает"
"Горутина 2 ожидает"
"Отправляем один сигнал"
"Горутина 3 проснулась"
"Отправляем второй сигнал"
"Горутина 1 проснулась"
Пример с проверкой условия
Покажем использование метода Signal в связке с проверкой условия в цикле:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
ready := false
go func() {
mu.Lock()
defer mu.Unlock()
for !ready {
fmt.Println("Ожидаем готовности")
cond.Wait()
}
fmt.Println("Условие выполнено!")
}()
time.Sleep(100 * time.Millisecond)
mu.Lock()
fmt.Println("Меняем состояние")
ready = true
cond.Signal()
mu.Unlock()
time.Sleep(100 * time.Millisecond)
}
Результат выполнения кода:
"Ожидаем готовности"
"Меняем состояние"
"Условие выполнено!"
Смотрите также
-
метод
sync.Cond.Broadcast,
который пробуждает все ожидающие горутины -
метод
sync.Cond.Wait,
который переводит горутину в ожидание сигнала -
функцию
sync.NewCond,
которая создает новую условную переменную -
тип
sync.Cond,
представляющий условную переменную