Здесь два момента
go list[i].Request(i)
гарантировано инициирует поток, но вовсе не обязательно запускает и this.is_sync = true
не исполняется. То есть может быть инициировано сколь угодно много горутин привязанных к одной Loc struct. Приоритет исполнения рутин в Go не детерменирован.
- Параметры в функцию передаются копированием значения, то есть вызов f
unc (this Loc) IsSync() bool
провоцирует полное копирование Loc, который может быть в работе. Что бы избежать копирования передавайте ссылкой.
В рамках вашей архитетуры(что бы не менять код сильно) так должно работать
package main
import (
"fmt"
"sync/atomic"
"time"
)
// наша структура
type Loc struct {
is_sync *int32
Value int
}
// метод, который говорит, можно ли запускать метод Request
func (this *Loc) IsSync() bool { //Передавайте параметр ссылкой, что бы избежать копирования
return (atomic.LoadInt32(this.is_sync) != 0)
}
// основной запрос, который может длиться несколько секунд
func (this *Loc) Request(val int) {
defer func() {
atomic.StoreInt32(this.is_sync, 0)
fmt.Println("End")
}()
fmt.Println("Request...")
this.Value = val
time.Sleep(time.Second)
}
var list []Loc
func init() {
list = append(list, Loc{is_sync: new(int32)})
}
func main() {
c := time.Tick(time.Second * 2)
for range c {
for i := 0; i < len(list); i++ {
if list[i].IsSync() { // если ещё не пришло время, то пропускаем
continue
}
atomic.StoreInt32(list[i].is_sync, 1) //флаг нужно выставить прямо здесь, а не дожидаясь исполнения рутины
go list[i].Request(i)
}
}
}