I am new to GO. I am specifically trying to add values to an array in parallel using locks (i do not want to use channels). But somehow my answer is not correct. I have tried both approaches. Passing a pointer to slice and Passing the slice itself. I am not looking for a global lock variable.
Method 1 (Passing pointer)
type locks_block struct {
population int
mux sync.Mutex
}
func incr(ar *[] locks_block){
for i:=0;i<len(*ar);i++ {
(*ar)[i].mux.Lock()
(*ar)[i].population = (*ar)[i].population+1;
(*ar)[i].mux.Unlock()
}
}
func main() {
arr := make([]locks_block,5);
go incr(&arr);
go incr(&arr);
go incr(&arr);
go incr(&arr);
fmt.Println(arr);
}
Method 2 (Passing slice)
type locks_block struct {
population int
mux sync.Mutex
}
func incr(ar [] locks_block){
for i:=0;i<len(ar);i++ {
ar[i].mux.Lock()
ar[i].population = ar[i].population+1;
ar[i].mux.Unlock()
}
}
func main() {
arr := make([]locks_block,5);
go incr(arr);
go incr(arr);
go incr(arr);
go incr(arr);
fmt.Println(arr);
}
The output is not correct in either case.
It appears you are using the lock correctly, but are not waiting for the goroutines to "finish" before printing arr
. Try adding a small <-time.After(time.Second)
, or using WaitGroup, or using select
to wait for all goroutines to finish, or placing the fmt.Println(ar[i].population)
inside the goroutines to see the results you want to see!
Same thing happens if you just start a bunch of goroutines without waiting for them to finish.
Here is a complete working example, with an extra 'id' for each goroutine, for clarity. Notice that the ordering of goroutines is not consistent!
package main
import (
"fmt"
"sync"
"time"
)
type locks_block struct {
population int
mux sync.Mutex
}
func incr(id int, ar []locks_block) {
for i := 0; i < len(ar); i++ {
ar[i].mux.Lock()
ar[i].population = ar[i].population + 1
fmt.Printf("goroutine #%v, population %v\n", id, ar[i].population)
ar[i].mux.Unlock()
}
}
func main() {
arr := make([]locks_block, 5)
go incr(1, arr)
go incr(2, arr)
go incr(3, arr)
go incr(4, arr)
// this should give the goroutines enough time
<-time.After(time.Millisecond * 500)
fmt.Println(arr)
}