如何避免在此golang程序中出现死锁?

Here is my program which is producing deadlock, how do I avoid it and what is the recommended pattern to handle this kind of situation.

The problem is after timeout how do I detect that there is no reader on my channel ?

var wg sync.WaitGroup

func main() {   
    wg.Add(1)
    c := make(chan int)
    go readFromChannel(c, time.After(time.Duration(2)*time.Second))
    time.Sleep(time.Duration(5) * time.Second)
    c <- 10
    wg.Wait()
}

func readFromChannel(c chan int, ti <-chan time.Time) {
    select {
    case x := <-c:
        fmt.Println("Read", x)
    case <-ti:
        fmt.Println("TIMED OUT")
    }
    wg.Done()
}

You have an unbuffered channel. According to the docs:

If the channel is unbuffered, the sender blocks until the receiver has received the value. If the channel has a buffer, the sender blocks only until the value has been copied to the buffer

By changing the channel to being buffered, we can avoid deadlock.

c := make(chan int, 10) // holds 10 ints

I also suggest reading https://golang.org/doc/effective_go.html#channels, it's got some good stuff in there related to channels.

So, lets look at what's really going on in your source. You have two goroutines (there's more than two, but we're going to focus on the explicit ones), main and readFromChannel.

Lets look at what readFromChannel does:

if channel `c` is not empty before `ti` has expired, print its contents and return, after signalling its completion to wait group.
if `ti` has expired before `c` is not empty, print "TIMED OUT" and return, after signalling its completion to wait group.

now Main:

adds to waitgroup 
make a channel `c`
start a goroutine `readFromChannel`
sleep for 5 seconds
send 10 to channel `c`
call wait for waitgroup

Now, lets go through the flow of execution for your code, concurrently (your code may/ may not execute in this order every time, keep that in mind)

1) wg.Add(1)
2) c := make(chan int)
3) go readFromChannel(c, time.After(time.Duration(2)*time.Second))
#timer ti starts#
4) time.Sleep(time.Duration(5) * time.Second)
#MAIN Goroutine begins sleep
#timer ti expires#
5) case <-ti:
6) fmt.Println("TIMED OUT")
7) wg.Done()
# readFromChannel Goroutine returns #
#MAIN Goroutine exits sleep#
8) c<-10
9) ......#DEADLOCK#

Now you can guess why you got a deadlock. In go, non buffered channels will block until something happens on the other end of the channel, regardless of whether you're sending or receiving. So c <- 10 will block until something reads from the other end of c, but the goroutine you had for that has dropped out of the picture 2 seconds ago. Therefore, c blocks forever, and since main is the last goroutine left, you get a Deadlock.

How to prevent it? When using channels, ensure that there's always a receive at the other end of the channel for every send. You can also use a buffered channel, but in your code above, it would not be the "right" solution.

Here's my fix for the deadlock:

func main() {
    wg.Add(1)
    c := make(chan int)
    go readFromChannel(c, time.After(time.Duration(2)*time.Second))
    time.Sleep(time.Duration(5) * time.Second)
    c <- 10
    wg.Wait()
}

func readFromChannel(c chan int, ti <-chan time.Time) {
        // the forloop will run forever
    loop: // **
    for {
        select {
            case x := <-c:
                    fmt.Println("Read", x)
                    break loop // breaks out of the for loop and the select **
            case <-ti:
                    fmt.Println("TIMED OUT")
            }
    }
    wg.Done()
} 

** see this answer for details

Your problem is that you are using select statement but you are not using inside a goroutine.

go func() {
    for {
        select {
        case x := <-c:
            fmt.Println("Read", x)
        case <-ti:
            fmt.Println("TIMED OUT")
        }
    }
}()

Getting the values out of different concurrently executing goroutines can be accomplished with the select keyword, which closely resembles the switch control statement and is sometimes called the communications switch.

Using a send operation in a select statement with a default case guarantees that the send will be non-blocking! If there are no cases, the select blocks execution forever.

https://play.golang.org/p/Ai1ggveb4s

This is an older question, but i'm diving deep into learning channels myself and found this here.

I think you just need to close the channel after your done sending on it?

Code:

func main() {
    wg.Add(1)
    c := make(chan int)
    go readFromChannel(c, time.After(time.Duration(2)*time.Second))
    time.Sleep(time.Duration(5) * time.Second)
    c <- 10
    close(c) // <- CLOSE IT HERE
    wg.Wait()
}
func main() {

    wg.Add(1)
    c := make(chan int)
    go func() {
        c <- 10

    }()
    go readFromChannel(c, time.After(time.Duration(2)*time.Second))
    time.Sleep(time.Duration(5) * time.Second)

    wg.Wait()

}//This will read without deadlock

func main() {
    wg.Add(1)
    c := make(chan int)

    go readFromChannel(c, time.After(time.Duration(2)*time.Second))
    time.Sleep(time.Duration(5) * time.Second)

    go func() {
        c <- 10

    }()
    wg.Wait()

}//Time out without deadlock