I was trying to implement Heap's Algorithm in go using channels. The code below is working fine when just printing the slices on the screen, but when using channels to delivery the arrays to a for/range loop on main function some unexpected behaviour occurs and the slices/arrays are printed in duplicity and not all permutations are sent. I thought that maybe i'm closing the channel earlier than the main function is able to print the results but i wouldn't expect that double print. Why is this happening and how can i make it work.

``````package main

import "fmt"

func perm(a []int64) {
var n = len(a)
var c = make([]int, n)
fmt.Println(a)
i := 0
for i < n {
if c[i] < i {
if i%2 == 0 {
a[0], a[i] = a[i], a[0]
} else {
a[c[i]], a[i] = a[i], a[c[i]]
}
fmt.Println(a)
c[i]++
i = 0
} else {
c[i] = 0
i++
}
}
}

func permch(a []int64, ch chan<- []int64) {
var n = len(a)
var c = make([]int, n)
ch <- a
i := 0
for i < n {
if c[i] < i {
if i%2 == 0 {
a[0], a[i] = a[i], a[0]
} else {
a[c[i]], a[i] = a[i], a[c[i]]
}
ch <- a
c[i]++
i = 0
} else {
c[i] = 0
i++
}
}
close(ch)
}

func main() {
var i = []int64{1, 2, 3}
fmt.Println("Without Channels")
perm(i)
ch := make(chan []int64)
go permch(i, ch)
fmt.Println("With Channels")
for slc := range ch {
fmt.Println(slc)
}

}
``````

2个回答

It looks like `permch` is modifying `a` at the same time as `main` is printing it, so your output is garbled.

I can think of three easy fixes:

1. Guard access to `a` with a mutex.
2. Put a copy of `a` on the channel:
3. Have some kind of return signal from main that it has printed and `permch` can continue. (don't really recommend this, but it works).

Number 2 is pretty simple:

``````a2 := make([]int64, len(a))
copy(a2,a)
ch <- a2
``````

and is what I would recommend.

For #1, just declare a `var m sync.Mutex` as a package variable and `Lock` is anytime you read or modify `a`. This is a race condition though between the reader and the next modification, as you pointed out, so it probably isn't a good solution after all.

fixed version on playground using #3

dswm97353 当我尝试使用Mutexes时，我可以使比赛检测程序静音，但无法获取我想要的是无频道版本的行为.play.golang.org / p / fSt9MfIyOi
3 年多之前 回复
dowjgrm6787 它对我不起作用，正如我预期的那样：play.golang.org/p/QuD0aE3tQH
3 年多之前 回复
doushibu2453 是的＃1在那种比赛条件下不太好。 查看修改。
3 年多之前 回复
dongyanjing5975 您能告诉我如何实施＃1或＃2吗？ 我认为添加另一个从main到goroutine的信号通道有点麻烦。 我试过使用内置的copy（）和make（）创建一个新的基础数组，但是我认为问题取决于在permch更改它的同时主要打印该数组。 而且我真的不知道如何使用互斥锁，因为我可以将部分锁定在更改数组的permch中，但是它不能保证它将等待main（）打印数组。
3 年多之前 回复

</ div>

### 原文

Your problem is that slices are reference types, and are being accessed in multiple goroutines. In `perm`, you're printing `a` directly as you finish processing it at each step. In `permch`, you're sending `a` over the channel, but then immediate starting to modify it again. Since each slice sent over the channel refers to the same underlying array, you have a race condition as to whether your next loop iteration alters `a` or your `Println()` call in main gets to that array first.

In general, if you're running into unexpected behavior in any program using goroutines, you probably have a race condition. Run the program with the `-race` flag to see where.

Edit: also, closing a channel has no effect on a routine reading from the channel. A channel can continue to be read until its buffer is empty, at which point it will start returning the zero value for that type instead. Range loops over a channel will only terminate once the channel is closed and its buffer is empty.