This is the 30th day of my participation in the August Challenge

This article appears in my column:Let’s Golang

A common deadlock situation in Golang concurrent operations

What is a deadlock? In the coroutine of Go a deadlock is usually a permanent block, you take my stuff, you want me to give it to you first and then give it to me, I take your stuff and then ask you to give it to me first, or I don’t give it to you. We both feel that way, and we can’t solve this.

The first case: no cache capability of the pipeline, write their own read

Code first:

func main(a) {
    ch := make(chan int.0)
​
    ch <- Awesome!
    x := <- ch
    fmt.Println(x)
}
Copy the code

We can see that this is a pipe with no caching capability, and then we write 666 into it, and then we go to the pipe and read it. There are bound to be problems! A cache free pipe, no one to read, you can’t write, no one to write, you can’t read, this is a deadlock!

fatal error: all goroutines are asleep - deadlock!
Copy the code

The solution is simple: create two coroutines, one to write and one to read.

Second case: Coroutine is late

func main(a) {
    ch := make(chan int.0)
    ch <- Awesome!
    go func(a) {
        <- ch
    }()
}
Copy the code

As we can see, this coroutine opens after the number is written to the pipe, which cannot be written because no one is reading it, and then writing to the pipe is blocked. At this time you have doubts, is not open up a coroutine reading? But that coroutine opens after the write pipe, and if you can’t write the pipe, you can’t open the coroutine.

Third case: when pipeline read and write, each request each other to read/write first

Deadlock occurs if you require each other to read/write first and then read/write yourself.

func main(a) {
    chHusband := make(chan int.0)
    chWife := make(chan int.0)
​
    go func(a) {
        select {
        case <- chHusband:
            chWife<- 888.
        }
    }()
​
    select {
        case <- chWife:
            chHusband <- 888}}Copy the code

Take a look at the wife first, as long as chWife can read out, that is, the wife is rich, give the husband a big red envelope of 888.

Look at my husband’s coroutine. I can’t see it. Why? The husband also said that as long as he has money to give his wife a bag of eight hundred and eighty-eight big red envelopes.

Two people all say oneself have no money, the husband also can’t send red envelope to the wife, the wife also can’t send red envelope to the husband, this is deadlock!

Fourth case: read and write locks block each other, forming an invisible deadlock

Let’s take a look at the code:

func main(a) {
    var rmw09 sync.RWMutex
    ch := make(chan int.0)
​
    go func(a) {
        rmw09.Lock()
        ch <- 123
        rmw09.Unlock()
    }()
​
    go func(a) {
        rmw09.RLock()
        x := <- ch
        fmt.Println("Read",x)
        rmw09.RUnlock()
    }()
​
    for {
        runtime.GC()
    }
}
Copy the code

If the first coroutine holds the write-only lock, the other coroutine cannot hold the read-only lock. The first coroutine cannot write because the other coroutine has not been read.

If the second coroutine holds the read-only lock first, the other coroutine cannot hold the write-only lock, so the second coroutine cannot read because the other coroutine did not write.