Почему эти горутины не блокируют? - PullRequest
0 голосов
/ 26 мая 2018

Я ожидаю, что эти две программы будут блокироваться навсегда по причинам, указанным ниже, но это не так.Почему?

  1. Канал не имеет буфера и будет ожидать получения receive().

  2. send() удерживать блокировку так num := <-s.ch в receive() не имеет возможности выполнить.

  3. Блокировать навсегда

Что не так?

package main

import (
    "sync"
    "fmt"
)

type S struct {
    mu sync.Mutex
    ch chan int
    wg sync.WaitGroup
}

func (s *S) send() {
    s.mu.Lock()
    s.ch <- 5
    s.mu.Unlock()
    s.wg.Done()
}
func (s *S) receive() {
    num := <-s.ch
    fmt.Printf("%d\n", num)
    s.wg.Done()
}

func main() {
    s := new(S)
    s.ch = make(chan int)
    s.wg.Add(2)
    go s.send()
    go s.receive()
    s.wg.Wait()
}

1 Ответ

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

Ваш метод receive() не использует блокировку, поэтому send() удержание блокировки не влияет на receive().

И так как send() и receive() работают самостоятельноgoroutine, send() доберется до точки, где он отправляет значение 5 на канал, и, таким образом, прием в receive() может продолжаться, и он будет печатать его в следующей строке.

Также обратите внимание, что для использования каналов из нескольких программ вам не требуется «внешняя» синхронизация.Каналы безопасны для одновременного использования, гонки данных не могут быть спроектированы.Подробнее см. Если я правильно использую каналы, нужно ли мне использовать мьютексы?

Если метод receive() также использует блокировку следующим образом:

func (s *S) receive() {
    s.mu.Lock()
    num := <-s.ch
    s.mu.Unlock()
    fmt.Printf("%d\n", num)
}

Тогда да, ничего не будет напечатано, потому что получение не может произойти, пока send() не снимет блокировку, но это не может произойти, пока кто-то не получит от канала.

И в этом случае программа завершит работучерез 1 секунду, ничего не печатая, потому что, когда сон закончится, основная программа завершится, как и все ваше приложение.Он не ждет завершения других неосновных процедур.Подробнее см. Нет вывода из goroutine в Go .

Редактировать:

Да, вы неправильно поняли блокировку.Блокировка sync.Mutex блокирует только само значение мьютекса, но не блокирует все значение структуры (не может).И «сам блокирует значение» означает, что если другая программа также вызывает свой метод Mutex.Lock(), этот вызов будет блокироваться до тех пор, пока блокировка не будет снята путем вызова метода Mutex.Unlock().Когда он разблокирован, процедура, заблокированная при вызове Mutex.Lock(), будет продолжать блокировать мьютекс и возвращаться.

...