Мне нужен способ передачи сигналов от одной основной программы, неизвестного числа других программ, несколько раз. Мне также нужно, чтобы эти другие goroutines набрали select
для нескольких элементов, так что ожидание в ожидании (вероятно) не вариант. Я нашел следующее решение:
package main
import (
"context"
"fmt"
"sync"
"time"
)
type signal struct {
data []int
channels []chan struct{}
}
func newSignal() *signal {
s := &signal{
data: make([]int, 0),
channels: make([]chan struct{}, 1),
}
s.channels[0] = make(chan struct{})
return s
}
func (s *signal) Broadcast(d int) {
s.data = append(s.data, d)
s.channels = append(s.channels, make(chan struct{}))
close(s.channels[len(s.data)-1])
}
func test(s *signal, wg *sync.WaitGroup, id int, ctx context.Context) {
for i := 0; ; i += 1 {
select {
case <-s.channels[i]:
if id >= s.data[i] {
fmt.Println("Goroutine completed:", id)
wg.Done()
return
}
case <-ctx.Done():
fmt.Println("Goroutine completed:", id)
wg.Done()
return
}
}
}
func main() {
s := newSignal()
ctx, cancel := context.WithCancel(context.Background())
wg := sync.WaitGroup{}
wg.Add(3)
go test(s, &wg, 3, ctx)
go test(s, &wg, 2, ctx)
go test(s, &wg, 1, ctx)
s.Broadcast(3)
time.Sleep(1 * time.Second)
// multiple broadcasts is mandatory
s.Broadcast(2)
time.Sleep(1 * time.Second)
// last goroutine
cancel()
wg.Wait()
}
Детская площадка: https://play.golang.org/p/dGmlkTuj7Ty
Есть ли более элегантный способ сделать это? Тот, который использует только встроенные библиотеки. Если нет, то безопасное ли это решение? По крайней мере, я считаю, что это безопасно, так как оно работает для большого количества программ (я провёл с ним некоторое тестирование).
Чтобы быть кратким, вот что я хочу:
- Основная программа (назовите ее
M
) должна иметь возможность сигнализировать с некоторыми данными (назовите ее d
) о некотором неизвестном количестве других программ (назовите их n
для 0...n
), несколько раз, с каждая процедура, выполняющая действие на основе d
каждый раз M
, должна иметь возможность сигнализировать все о других n
программах с определенными (числовыми) данными, несколько раз - Каждая процедура в
n
будет либо завершаться самостоятельно (в зависимости от контекста), либо после выполнения некоторой операции с d
и определения ее судьбы. Он будет выполнять эту проверку столько раз, сколько ему было сообщено, пока он не умрет. - Мне не разрешено каким-либо образом отслеживать
n
программы (например, имея карту каналы для перебора и итерации)
В моем решении срезы каналов не представляют подпрограммы: они фактически представляют сигналы, которые транслируются. Это означает, что если я транслирую два раза, а затем раскручивается программа, он проверит оба сигнала перед сном в блоке select
.