Go Locks в ломтик структуры - PullRequest
0 голосов
/ 05 мая 2018

Я новичок в GO. Я специально пытаюсь добавить значения в массив параллельно, используя блокировки (я не хочу использовать каналы). Но почему-то мой ответ не верен. Я испробовал оба подхода. Передача указателя на срез и передача самого среза. Я не ищу глобальную переменную блокировки.

Метод 1 (проходной указатель)

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

Метод 2 (проходящий срез)

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

Вывод неверный в любом случае.

1 Ответ

0 голосов
/ 05 мая 2018

Похоже, что вы используете блокировку правильно, но не ждете, пока программы завершат работу, прежде чем печатать arr. Попробуйте добавить маленькую <-time.After(time.Second), либо использовать WaitGroup, либо использовать select, чтобы дождаться завершения всех процедур, либо поместить fmt.Println(ar[i].population) внутри процедур, чтобы увидеть результаты, которые вы хотите увидеть!

То же самое происходит, если вы просто запускаете кучу горутин, не дожидаясь их завершения.

Вот полный рабочий пример с дополнительным идентификатором для каждой программы, для ясности. Обратите внимание, что порядок сортировки не соответствует!

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