20426


Golangで下記のコードを実行するとdeadlockを起こします。  
SetValueの中で、引数として与えられた`value`を`g.CH`に渡す時にdeadlockになっているようです。  
なぜ、deadlockになってしまうのでしょうか?

[code]

    
    package main
    
    import (
        "fmt"
    )
    
    type GeneratorChannel struct {
        X  int
        CH chan int
    }
    
    func New() *GeneratorChannel {
        s := GeneratorChannel{}
        s.CH = make(chan int)
        return &s
    }
    
    func (g *GeneratorChannel) SetValue(value int) {
        g.X = value
        g.CH <- g.X
    
    }
    func (g *GeneratorChannel) GetChannelValue() int {
        return <-g.CH
    }
    
    func main() {
        g := New()
        g.SetValue(4)
        fmt.Println(g.GetChannelValue())
    
    }
    
    
    
    
[/code]


CC BY-SA 3.0
2015-12-26T14:34:58.380
20405
2015-12-28T02:19:10.970
2015-12-27T13:39:35.893
5246
5246
question
go
Structの中にあるチャンネルに値をsendするとdeadlockする


>
[code]

>     s.CH = make(chan int)
>  
[/code]

バッファなしチャネル（容量0）として作成しているため、送信操作`g.CH <- g.X`がブロッキングしています。このとき同時に受信操作`return
<-g.CH`が行われれば、送受信が成立してブロッキング解除されますが、掲示コードでは送受信を同じGoroutineで行おうとしているため、永遠に受信が完了せずデッドロックしています。

**解決策1：**
チャネルの容量を1以上に設定する。送信された値は一旦バッファリングされ、後続の受信操作にて値が取り出されます。いずれの操作もブロッキングしないため、デッドロックは回避されます。

[code]

    s.CH = make(chan int, 1)
    
[/code]

ただしこの方法では、チャネルのバッファがあふれると再びデッドロックします。チャネル容量が1の場合、2つの値を連続送信するとデッドロックします。

**解決策2：**
送信操作を受信とは異なるGoroutine上で実行する。異なるGoroutine間でのチャネル通信となり、デッドロックが回避されます。（チャネルは本来Goroutine間の同期通信に用いる仕組みですから、こちらの方が正攻法かと思います。）

[code]

    go g.SetValue(4)
    
[/code]


CC BY-SA 3.0
2015-12-28T02:19:10.970
20426
2015-12-28T02:19:10.970
49
20405
answer