Go Locks in a slice of struct

Issue

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.

Solution

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)
}

Answered By – aerth

Answer Checked By – Gilberto Lyons (GoLangFix Admin)

Leave a Reply

Your email address will not be published.