douwei1128 2015-04-06 20:56
浏览 47
已采纳

高朗:学习goroutine使我陷入僵局

I'm a GO newbie and I'm trying to figure out how does goroutines work and how to synchronize them. This is a simple program I wrote to learn something about them:

package main

import (
        "fmt"
        "sync"
        "time"
)

func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
        time.Sleep(delay)
        fmt.Println(message)
        wg.Done()
}

func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
        c := a + b
        chan1 <- c
        //close(chan1)
        wg.Done()
}

func printer(chan1 chan int, wg *sync.WaitGroup) {
        for result := range chan1 {
                //result := <-chan1
                //time.Sleep(2000 * time.Millisecond)
                fmt.Println(result)
        }
        close(chan1)
        wg.Done()
}

func main() {
        //var wg sync.WaitGroup
        wg := &sync.WaitGroup{}

        fmt.Println("Start...")

        wg.Add(1)
        go printAfterDelay(2000*time.Millisecond, "Try", wg)

        chan1 := make(chan int)
        wg.Add(1)
        go add(5, 4, chan1, wg)

        wg.Add(1)
        go add(3, 1, chan1, wg)

        wg.Add(1)
        go printer(chan1, wg)

        //time.Sleep(3000 * time.Millisecond)
        wg.Wait()

        fmt.Println("End")
}

The add function takes two int, sums them and pass the result to a chan. The printer function takes the results from the chan and print them. The two funtions are called in main() as goroutines, so i also passed a WaitGroup as a pointer, that is incremented before calling the goroutines and decremented when the functions end.

Anyway when I execute the compiled program it prints:

Start...
9
4
Try
fatal error: all goroutines are asleep - deadlock!
goroutine 16 [semacquire]:
sync.runtime_Semacquire(0x18334008)
  /usr/lib/go/src/pkg/runtime/sema.goc:199 +0x37
sync.(*WaitGroup).Wait(0x183240e0)
  /usr/lib/go/src/pkg/sync/waitgroup.go:129 +0x12d
main.main()        
  /home/ettore/go/src/example/goroutine/main.go:52 +0x1e5

goroutine 19 [finalizer wait]:
runtime.park(0x80599e0, 0x814f000, 0x814e3e9)
  /usr/lib/go/src/pkg/runtime/proc.c:1369 +0x94
runtime.parkunlock(0x814f000, 0x814e3e9)       
  /usr/lib/go/src/pkg/runtime/proc.c:1385 +0x3
frunfinq()        
  /usr/lib/go/src/pkg/runtime/mgc0.c:2644 +0xc5
runtime.goexit()        
  /usr/lib/go/src/pkg/runtime/proc.c:1445

goroutine 23 [chan receive]:
main.printer(0x1831a090, 0x183240e0)        
  /home/ettore/go/src/example/goroutine/main.go:23 +0x46
created by main.main        
  /home/ettore/go/src/example/goroutine/main.go:49 +0x1d7

Where and what is the problem(s)?

Thanks!

  • 写回答

1条回答 默认 最新

  • dongxian8048 2015-04-07 02:30
    关注

    The following works. By that I mean that it doesn't deadlock. Since you have the printer function in a range loop over the channel, it'll automatically stop after the channel is closed. I added the 3 sec delay near the end to give the try loop time to print. Read the documentation though. It'll explain 100% of these details.

    package main
    
    import (
            "fmt"
            "sync"
            "time"
    )
    
    func printAfterDelay(delay time.Duration, message string, wg *sync.WaitGroup) {
            time.Sleep(delay)
            fmt.Println(message)
    
    }
    
    func add(a int, b int, chan1 chan int, wg *sync.WaitGroup) {
            c := a + b
            chan1 <- c
            wg.Done()
    }
    
    func printer(chan1 chan int, wg *sync.WaitGroup) {
            for result := range chan1 {
                    fmt.Println(result)
            }
    }
    
    func main() {
            //var wg sync.WaitGroup
            wg := &sync.WaitGroup{}
    
            fmt.Println("Start...")
    
            go printAfterDelay(2000*time.Millisecond, "Try", wg)
    
            chan1 := make(chan int)
            wg.Add(1)
            go add(5, 4, chan1, wg)
    
            wg.Add(1)
            go add(3, 1, chan1, wg)
    
            go printer(chan1, wg)
    
            time.Sleep(3000 * time.Millisecond)
            wg.Wait()
        close(chan1)
    
            fmt.Println("End")
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 unity第一人称射击小游戏,有demo,在原脚本的基础上进行修改以达到要求
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)