Канал с одним токеном сериализует изменение числа, а закрытие отдельного канала останавливает работников. При начальном значении 1 итог — 1024.
Конкурентное удвоение числа с использованием только каналов
Канал с одним токеном сериализует изменение числа, а закрытие отдельного канала останавливает работников. При начальном значении 1 итог — 1024.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Имеется глобальная переменная (целочисленная) и десять горутин, каждая из которых:
- Умножает эту переменную на 2.
- Останавливается, когда значение достигает или превышает 1000. Главная горутина обязана прервать работу всех остальных горутин и вывести окончательный результат.
Требования:
- Запрещено применять пакеты sync (мьютексы, WaitGroup) и sync/atomic.
- Весь механизм синхронизации и передачи данных должен быть построен исключительно на каналах.
Ответ
Канал с одним токеном сериализует изменение числа, а закрытие отдельного канала останавливает работников. При начальном значении 1 итог — 1024.
Начальное значение в условии не задано: выберем 1. Для нуля или отрицательного числа удвоение не достигнет порога, поэтому такие начальные значения требуют отдельной проверки.
package main
import "fmt"
var value = 1
func main() {
token := make(chan struct{}, 1)
stop := make(chan struct{})
finished := make(chan struct{}, 10)
result := make(chan int, 1)
token <- struct{}{}
for i := 0; i < 10; i++ {
go func() {
defer func() { finished <- struct{}{} }()
for {
select {
case <-stop:
return
case <-token:
if value < 1000 { value *= 2 }
if value >= 1000 {
result <- value
return
}
token <- struct{}{}
}
}
}()
}
final := <-result
close(stop)
for i := 0; i < 10; i++ { <-finished }
fmt.Println(final)
}
Достигший порога работник не возвращает токен, поэтому никто не удваивает число дальше. main закрывает stop и ждёт подтверждения завершения всех десяти горутин. Все обращения к общей переменной защищены передачей единственного токена.