Функция sync.NewCond
Функция sync.NewCond создает новую условную переменную типа *sync.Cond,
которая используется для синхронизации горутин при работе с общими ресурсами.
В качестве единственного параметра функция принимает интерфейс sync.Locker -
обычно это мьютекс типа sync.Mutex или sync.RWMutex.
Возвращаемое значение - указатель на структуру sync.Cond,
которая предоставляет методы для ожидания и уведомления горутин об изменении состояния.
Синтаксис
sync.NewCond(l sync.Locker) *sync.Cond
Пример
Давайте создадим условную переменную с обычным мьютексом и используем ее для синхронизации двух горутин:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
ready := false
// Горутина, которая ждет изменения состояния
go func() {
mu.Lock()
for !ready {
cond.Wait()
}
fmt.Println("Condition met, proceeding...")
mu.Unlock()
}()
// Горутина, которая меняет состояние
go func() {
time.Sleep(2 * time.Second)
mu.Lock()
ready = true
cond.Signal()
fmt.Println("Signal sent")
mu.Unlock()
}()
time.Sleep(3 * time.Second)
}
Результат выполнения кода:
"Signal sent"
"Condition met, proceeding..."
Пример
Давайте используем условную переменную для синхронизации нескольких горутин с помощью метода Broadcast:
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
count := 0
var wg sync.WaitGroup
// Запускаем 3 горутины, которые ждут сигнала
for i := 0; i < 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
mu.Lock()
for count < 10 {
cond.Wait()
}
fmt.Printf("Goroutine %d: count is %d\n", id, count)
mu.Unlock()
}(i)
}
// Увеличиваем счетчик и отправляем широковещательный сигнал
mu.Lock()
count = 10
cond.Broadcast()
mu.Unlock()
wg.Wait()
}
Результат выполнения кода:
"Goroutine 2: count is 10"
"Goroutine 0: count is 10"
"Goroutine 1: count is 10"
Пример
Давайте создадим условную переменную с мьютексом для реализации паттерна "производитель-потребитель":
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
queue := make([]int, 0, 5)
var wg sync.WaitGroup
// Потребитель
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
for len(queue) == 0 {
cond.Wait()
}
item := queue[0]
queue = queue[1:]
fmt.Printf("Consumed: %d\n", item)
mu.Unlock()
}()
// Производитель
mu.Lock()
queue = append(queue, 42)
cond.Signal()
fmt.Println("Produced: 42")
mu.Unlock()
wg.Wait()
}
Результат выполнения кода:
"Produced: 42"
"Consumed: 42"
Смотрите также
-
структуру
sync.Cond,
которая представляет условную переменную для синхронизации горутин -
метод
sync.Cond.Wait,
который блокирует горутину до получения сигнала -
метод
sync.Cond.Signal,
который пробуждает одну ожидающую горутину -
метод
sync.Cond.Broadcast,
который пробуждает все ожидающие горутины