Как мы можем использовать каналы в Go вместо мьютекса? - PullRequest
13 голосов
/ 17 октября 2010

Каналы объединяют обмен данными - обмен значениями - с синхронизацией, гарантируя, что два вычисления (процедуры) находятся в известном состоянии.

Как можно использовать каналы в Google Go для выполнения функций мьютекса?

package main

import "sync"

var global int = 0
var m sync.Mutex

func thread1(){
    m.Lock()
    global = 1
    m.Unlock()
}

func thread2(){
    m.Lock()
    global = 2
    m.Unlock()
}

func main(){
   go thread1()
   go thread2()
}

Ответы [ 2 ]

22 голосов
/ 17 октября 2010

Пример использования канала в качестве мьютекса:

package main

var global int = 0
var c = make(chan int, 1)

func thread1(){
    <-c // Grab the ticket
    global = 1
    c <- 1 // Give it back
}

func thread2(){
    <-c
    global = 2
    c <- 1
}

func main() {
   c <- 1 // Put the initial value into the channel
   go thread1()
   go thread2()
}

Вы также можете использовать chan struct{} вместо chan int, чтобы уменьшить объем памяти. В него входит значение struct{}{} (тип struct{} и пустое содержимое {}). См. комментарий Ивана Блэка для примера.

5 голосов
/ 17 октября 2010

Если у вас есть канал c, который вы инициализируете с 1 элементом в нем, то вы можете «проверить» «мьютекс», удалив значение из канала (<-c). Вы можете «освободить» его, добавив значение обратно (c <- 1).

Так как оператор извлечения из канала a) является атомарным, и b) блокирует, пока есть что извлечь, он работает как мьютекс, так как если один поток выполнения уже извлечет его, в нем ничего не будет канал, и, таким образом, он будет блокироваться до тех пор, пока извлеченный им поток не вернет значение в канал для извлечения другим потоком.

...