作者热门文章
- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我想编写三个相互发送整数的并发 go 例程。现在,我的代码已正确编译,但在第一次执行后出现错误“抛出:所有 goroutines 都睡着了 - 死锁!”。我试图找到错误,但我无法在代码逻辑中找到任何错误。任何人都可以帮助我找到我的代码中的错误。我的代码如下。
package main
import "rand"
func Routine1(command12 chan int, response12 chan int, command13 chan int, response13 chan int) {
// z12 is a variable which stores the value comming from channel 2 and z13 is a variable which stores the value comming from channel 3.
z12 := 200
z13 := 200
m12 := false
m13 := false
y := 0
for i := 0; i < 20; i++ {
y = rand.Intn(100)
// If y's value is not 0 then the value will be sent to routine 2 or 3 according to prime or not.
// If y's value is 0 then process state (the varibles used by it means z12, z13) and channel state will be saved.[routine 1 is initiator]
if y == 0 {
print(z12, " z12 STATE SAVED\n")
print(z13, " z13 STATE SAVED\n")
// Routine 1 is initiator, it sends 0 to make other process to save the state.
y = 0
command12 <- y
command13 <- y
// Untill routine 2 and 3 does not send 0, process 1 is on channel saving state (it's process state is already saved).
// When routine 1 recives 0 from both other processes, channel is saved and routine 1 retuns to it's common routine procedure.
// When routine 1 recives 0 from any other processes, saving channel bettwen them is stopped.
// m12, m13 is used to mark whether 0 recived or not.
for m12 != true || m13 != true {
select {
case cmd1 := <-response12:
{
z12 = cmd1
if z12 != 0 {
print(z12, " z12 Channel Saving.... \n")
y = rand.Intn(100)
command12 <- y
}
if z12 == 0 {
m12 = true
print(" z12 Channel Saving Stopped \n")
}
}
case cmd2 := <-response13:
{
z13 = cmd2
if z13 != 0 {
print(z13, " z13 Channel Saving.... \n")
y = rand.Intn(100)
command13 <- y
}
if z13 == 0 {
m13 = true
print(" z13 Channel Saving Stopped \n")
}
}
}
}
// After saving process state it retuns to it's normal behaviour.
m12 = false
m13 = false
}
if y != 0 {
// If y value is not 0, routine 1 just sends int to other process according to prime or not and recives int accordingly.
if y%2 == 0 {
command12 <- y
}
if y%2 != 0 {
command13 <- y
}
select {
case cmd1 := <-response12:
{
z12 = cmd1
print(z12, " z12\n")
}
case cmd2 := <-response13:
{
z13 = cmd2
print(z13, " z13\n")
}
}
}
}
close(command12)
close(command13)
}
//Routine 2 (or 3) is not an initiator (means it can't send 0). When it recives 0 (from routine 1 or 3) it save the state of process and the state of the channel from which it recived).
// When it recives 0 from both other two routine, it saves all channel state and returns to it's common behaviour. [same in routine 3]
func Routine2(command12 chan int, response12 chan int, command23 chan int, response23 chan int) {
z21 := 200
z23 := 200
m21 := false
m23 := false
for i := 0; i < 20; i++ {
select {
case x, open := <-command12:
{
if !open {
return
}
if x != 0 && m23 != true {
z21 = x
print(z21, " z21\n")
}
if x != 0 && m23 == true {
z21 = x
print(z21, " z21 Channel Saving \n")
}
if x == 0 {
m21 = true
if m21 == true && m23 == true {
print(" z21 and z23 Channel Saving Stopped \n")
m23 = false
m21 = false
}
if m21 == true && m23 != true {
z21 = x
print(z21, " z21 Channel Saved \n")
}
}
}
case x, open := <-response23:
{
if !open {
return
}
if x != 0 && m21 != true {
z23 = x
print(z23, " z21\n")
}
if x != 0 && m21 == true {
z23 = x
print(z23, " z23 Channel Saving \n")
}
if x == 0 {
m23 = true
if m21 == true && m23 == true {
print(" z23 Channel Saving Stopped \n")
m23 = false
m21 = false
}
if m23 == true && m21 != true {
z23 = x
print(z23, " z23 Channel Saved \n")
}
}
}
}
if m23 == false && m21 == false {
y := rand.Intn(100)
if y%2 == 0 {
if y == 0 {
y = 10
response12 <- y
}
}
if y%2 != 0 {
if y == 0 {
y = 10
response23 <- y
}
}
}
if m23 == true && m21 != true {
y := rand.Intn(100)
response12 <- y
}
if m23 != true && m21 == true {
y := rand.Intn(100)
command23 <- y
}
}
close(response12)
close(command23)
}
func Routine3(command13 chan int, response13 chan int, command23 chan int, response23 chan int) {
z31 := 200
z32 := 200
m31 := false
m32 := false
for i := 0; i < 20; i++ {
select {
case x, open := <-command13:
{
if !open {
return
}
if x != 0 && m32 != true {
z31 = x
print(z31, " z21\n")
}
if x != 0 && m32 == true {
z31 = x
print(z31, " z31 Channel Saving \n")
}
if x == 0 {
m31 = true
if m31 == true && m32 == true {
print(" z21 Channel Saving Stopped \n")
m31 = false
m32 = false
}
if m31 == true && m32 != true {
z31 = x
print(z31, " z31 Channel Saved \n")
}
}
}
case x, open := <-command23:
{
if !open {
return
}
if x != 0 && m31 != true {
z32 = x
print(z32, " z32\n")
}
if x != 0 && m31 == true {
z32 = x
print(z32, " z32 Channel Saving \n")
}
if x == 0 {
m32 = true
if m31 == true && m32 == true {
print(" z32 Channel Saving Stopped \n")
m31 = false
m32 = false
}
if m32 == true && m31 != true {
z32 = x
print(z32, " z32 Channel Saved \n")
}
}
}
}
if m31 == false && m32 == false {
y := rand.Intn(100)
if y%2 == 0 {
response13 <- y
}
if y%2 != 0 {
response23 <- y
}
}
if m31 == true && m32 != true {
y := rand.Intn(100)
response13 <- y
}
if m31 != true && m32 == true {
y := rand.Intn(100)
response23 <- y
}
}
close(response13)
close(response23)
}
func main() {
// Three concurrent channels are created to pass integers to each other.
// command 12 used to send int and response12 is used to receive int from routine 1 to routine 2.
// response 12 used to send int and command 12 is used to receive int from routine 2 to routine 1. {so as for others}
command12 := make(chan int)
response12 := make(chan int)
command13 := make(chan int)
response13 := make(chan int)
command23 := make(chan int)
response23 := make(chan int)
go Routine1(command12, response12, command13, response13)
go Routine2(command12, response12, command23, response23)
Routine3(command13, response13, command23, response23)
}
最佳答案
正如其他人所说 - 您的代码太复杂,我无法快速找出其预期逻辑。无论如何,“技术分析”方法带来了一些好处。当将 Gosched 作为默认情况添加到选择语句时 和 使 channel 缓冲 - 然后代码不再死锁。虽然我不知道它在做什么,也不知道它是否按照你想要的去做。
在我看来,从代码来看,行为是不确定的(?)。无论如何,我认为原始代码可能被设计破坏了(例如,一些循环看起来像是在忙着等待,即使它们运行了 N 次硬编码,原文如此!),很抱歉这么说。
“工作”(== 谁知道它在做什么)代码:http://play.golang.org/p/dcUpeJ9EUa
PS:第 325 行的缓冲区大小 const 不能低于 4(通过每周试运行)并且似乎提供了另一种改变代码行为的方法。
关于go - throw 所有的 goroutines 都睡着了——僵局! ------- 谷歌GO的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8272760/
我是一名优秀的程序员,十分优秀!