2017-10-14 143 views
0

这里是我主要功能的主体;初学者级代码的死锁

c := make(chan int) 

go func() { 

    i := <-c 
    i++ 
    time.Sleep(100 * time.Millisecond) 

    c <-i 


}() 

time.Sleep(1 * time.Second) 
go func() { 
    i := <-c 
    i++ 
    time.Sleep(100 * time.Millisecond) 
    c <-i 

}() 

time.Sleep(1 * time.Second) 
fmt.Println(<-c) 

我越来越死锁error.even我试了waitgroups.hella撕开我的头发。

解释答案对我来说很好。

+2

没有写入'c',因此所有3个线程都被锁定读取。 – zerkms

+0

我刚刚在println之前加了“c < - 0”,它可以工作,但是当我在第一次去func之前添加它之后,我得到了同样的死锁error.wth发生了什么? –

+0

@KadirSusuz在产生第一个goroutine之前添加写入操作时,您正在尝试写入未缓冲的通道。此操作会阻塞,直到从通道读取值,但尚未启动goroutine以从中读取。解决方案将首先启动goroutines或创建一个缓冲通道。 – Gavin

回答

0

添加的最后一行之前:

c <- 0 

这样,你给它可以通过够程读取开始工作开始值。您也可以在最后一行前添加到都够程(发送信道)添加打印够程数和值:

fmt.Println("goroutine 1 value", i) 

这还可以看到如何在通道中的同一项目的3名可能的消费者的情况过去了。主办公室很可能会阅读该频道,并获得0。增加Sleep给别人一个机会。用睡眠时间玩,可以获得不同的结果。

+0

我刚刚在println之前添加了“c < - 0”,它的工作原理,但是当我在第一次去func之前添加它之后,我得到了同样的死锁error.wth发生了什么? –

+0

非常正确 - 因为那时候没有可以从频道读取的门厅。因此,写入频道被阻止,直到有人开始从频道中读取。尝试在起始读者之间进行书写。另一种方法:你可以让你的频道缓冲 - 这意味着它可以存储几个元素。规则是一样的:如果有新元素的空间,如果没有空间作家被封锁,你可以写信给频道。如果有读者,它会读取元素,从而为新的元素腾出空间。如何创建缓冲频道? make(chan int,10)' - 这里是10 buf len –

1

在写入之前,您正在阅读频道,因此所有事情都会陷入僵局,等待无法完成的阅读。

在打电话给Printf之前,您可以打c <- 0来打破僵局,但程序可以打印0,1或2.请注意,如果您在开始第一个goroutine之前先发送初始发送,则会出现同样的问题从另一个方面来说,发送没有可能的读取。

如果你说过你正在尝试做什么,这将会更容易帮助,因为它是我无法真正提供任何特定的指针。

+0

“,0是迄今为止最可能的结果。” ---这也是我的想法,但在play.golang上是2。在一台CPU上,机器2更有可能。 – zerkms

+0

在哪里放置第一次发送,你睡在哪里将是对单核心机器的主要影响,但是现在谁在运行单核心机器? :P如果你在第一次发送后立即睡眠,在多个内核上变得相当不可预测。 –

+0

我刚刚在println之前添加了“c < - 0”,它可以工作,但是当我在第一次去func之前添加它时,我得到了同样的死锁error.wth发生了什么? –

0

你有一个无缓冲的渠道,这意味着你的工作“同步”我的意思是当使用无缓冲的渠道,你需要一个作家和读者来实现一些尝试缓冲渠道,你可以尝试选择等待消息。 2 - 在写入之前,您正在读取未缓冲的通道,该通道将阻塞,直到写入操作发生。所以你从一个封闭的渠道中获得了2位读者(因为没有作家)。