Несколько воркеров одновременно увеличивают общий счётчик. Нужно сделать это на
атомарных операциях из sync/atomic, без мьютекса.
// Counter — счётчик для конкурентного использования. Нулевое значение готово к работе.
type Counter struct { /* … */ }
func (c *Counter) Inc()
func (c *Counter) Add(delta int64)
func (c *Counter) Value() int64
// Run запускает workers горутин, каждая perWorker раз вызывает c.Inc(),
// и возвращается, когда все они закончили.
func Run(c *Counter, workers, perWorker int)
Требования
- Ни один инкремент не теряется: после
Run(c, 2, 100000) значение ровно
на 200 000 больше, чем было.
Value можно вызывать одновременно с Inc и Add из других горутин.
- Мьютекс не используется, только
sync/atomic.
Run возвращается только после того, как все воркеры закончили. workers и
perWorker могут быть нулём.
- Код проходит
go test -race.
Пример
var c Counter
Run(&c, 2, 100000)
fmt.Println(c.Value()) // 200000
c.Add(-5)
fmt.Println(c.Value()) // 199995
// IncUpTo увеличивает счётчик на 1, только если текущее значение меньше limit.
// Возвращает true, если увеличил.
func (c *Counter) IncUpTo(limit int64) bool
- Даже при сотнях конкурентных вызовов значение не превышает
limit, и
число вызовов, вернувших true, равно ровно тому, на сколько счётчик вырос.
- Тоже без мьютекса.
Устно: чем atomic.Int64 лучше atomic.AddInt64(&x, 1) по обычному
int64? Когда атомиков недостаточно и нужен мьютекс?
Разбор и эталонное решение — после своей попытки: на собеседовании подсказок не будет.
Сначала попробуй сам — подсказки не дают готовый ответ.