这些goroutine的WaitGroup为什么不能正常工作?

This code is for a fairly simple demo for my programming language class. I'm trying to display a few different techniques that Go allows, like interfaces and concurrency, but I can't seem to get the WaitGroups to work right, so it keeps deadlocking on me at the end. My biggest question is: how do I get the WaitGroups to synchronize correctly and not deadlock the system when the goroutines stop? I'm most likely missing something obvious.

package main

import (
    "bufio"
    "fmt"
    "os"
    "sync"
)


func Reader(wg *sync.WaitGroup, message chan string, done chan bool){
defer wg.Done()
        reader := bufio.NewReader(os.Stdin)
        for {

            msg, _ := reader.ReadString('
')
            if msg == "exit
" {
                <-done
                return
            } else {
                message <- msg
            }

        }

 }

func main() {
    message := make(chan string)
    done := make(chan bool)
    wg := &sync.WaitGroup{}


    wg.Add(1)
    go Reader(wg, message, done) 


    wg.Add(1)
    go func(){
    defer wg.Done()
        for {
            select {
            case <-done:
                return
            case msg := <-message:
                fmt.Println("main: "+msg)
            }
        }

    }() 

    wg.Wait()
    close(message)
    close(done)


}

Your break statement in main breaks the select, not the for loop. Use return or a label instead:

go func() {
    defer wg.Done()
    for {
        select {
        case <-done:
            return // don't break here without label
        case msg := <-message:
            fmt.Println("main: " + msg)
        }
    }
}()

In addition, both functions try to receive from done. Reader should close the channel instead to signal completion:

func Reader(wg *sync.WaitGroup, message chan string, done chan bool) {
        defer wg.Done()
        defer close(done) // close channel to signal completion

        reader := bufio.NewReader(os.Stdin)
        for {
                msg, _ := reader.ReadString('
')
                if msg == "exit
" {
                        return
                } else {
                        message <- msg
                }
        }
}

Don't close the channel in main. Channels should always be closed on the sender's side.

Once you have done all that you should recognize that message and done are redunant. The whole program can be simplified to:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func Reader(message chan string) {
    defer close(message)

    reader := bufio.NewReader(os.Stdin)
    for {
        msg, _ := reader.ReadString('
')
        if msg == "exit
" {
            return
        } else {
            message <- msg
        }
    }
}

func main() {
    message := make(chan string)
    go Reader(message)

    for msg := range message {
        fmt.Println("main: " + msg)
    }
}