Мне трудно понять, как правильно использовать sync.Cond
. Из того, что я могу сказать, существует условие гонки между блокировкой Locker и вызовом метода Wait условия. Этот пример добавляет искусственную задержку между двумя строками в главной горутине для имитации состояния гонки:
package main
import (
"sync"
"time"
)
func main() {
m := sync.Mutex{}
c := sync.NewCond(&m)
go func() {
time.Sleep(1 * time.Second)
c.Broadcast()
}()
m.Lock()
time.Sleep(2 * time.Second)
c.Wait()
}
Это вызывает немедленную панику:
fatal error: all goroutines are asleep - deadlock! goroutine 1 [semacquire]: sync.runtime_Syncsemacquire(0x10330208, 0x1) /usr/local/go/src/runtime/sema.go:241 +0x2e0 sync.(*Cond).Wait(0x10330200, 0x0) /usr/local/go/src/sync/cond.go:63 +0xe0 main.main() /tmp/sandbox301865429/main.go:17 +0x1a0
Что я делаю неправильно? Как избежать этого очевидного состояния гонки? Есть ли лучшая конструкция синхронизации, которую я должен использовать?
Изменить: Я понимаю, что мне лучше объяснить проблему, которую я пытаюсь решить здесь. У меня есть длинный goroutine, который загружает большой файл и ряд других goroutines, которым необходим доступ к заголовкам HTTP, когда они доступны. Эта проблема сложнее, чем кажется.
Я не могу использовать каналы, потому что тогда только один goroutine получит значение. И некоторые из других goroutines будут пытаться получить заголовки долго после того, как они уже доступны.
Загружающий goroutine может просто хранить заголовки HTTP в переменной и использовать мьютексы для защиты доступа к ним. Однако это не дает возможность другим гортанам "подождать", чтобы они стали доступными.
Я думал, что оба sync.Mutex
и sync.Cond
вместе могут выполнить эту задачу, но кажется, что это невозможно.