Answer the question
In order to leave comments, you need to log in
How to solve the problem with DATA RACE?
The essence of the problem is that I have an array of some objects (structures). This structure has some properties and several methods. Bypassing this cycle by timer, I turn to the properties to determine whether it is necessary to call a certain method of this structure in a separate thread.
Here's a code example:
import (
"fmt"
"sync"
"time"
)
// наша структура
type Loc struct {
mutex sync.Mutex
is_sync bool
Value int
}
// метод, который говорит, можно ли запускать метод Request
func (this Loc) IsSync() bool {
return this.is_sync
}
// основной запрос, который может длиться несколько секунд
func (this *Loc) Request(val int) {
this.is_sync = true
defer func() {
this.is_sync = false
fmt.Println("End")
}()
fmt.Println("Request...")
this.Value = val
time.Sleep(time.Second)
}
var list []Loc
func init() {
list = append(list, Loc{})
}
func main() {
c := time.Tick(time.Second * 2)
for range c {
for i := 0; i < len(list); i++ {
if list[i].IsSync() { // если ещё не пришло время, то пропускаем
continue
}
go list[i].Request(i)
}
}
}
func (this Loc) IsSync() bool {
this.mutex.Lock()
s := this.is_sync
this.mutex.Unlock()
return s
}
Answer the question
In order to leave comments, you need to log in
There are two points here
go list[i].Request(i)
is guaranteed to initiate a thread, but does not necessarily start and this.is_sync = true
is not executed. That is, arbitrarily many goroutines tied to one Loc struct can be initiated. The execution priority of routines in Go is not deterministic.unc (this Loc) IsSync() bool
provokes a complete copy of Loc, which may be in operation. To avoid copying, pass a link.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)
}
}
}
You should look at the approach from the other side. Why do you need a cycle? Make it in every Request() goroutine. One goroutine per Loc object. To control (start/stop between iterations) use a channel.
You will reach the rest yourself, or you will not reach - who knows :)
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question