I'm trying to add nodes to a linked list concurrently using channels and goroutines. I seem to be doing be something wrong, however. Here's what I've written so far.
Currently, my print function is just repeating the 8th node. This seems to work on other linked lists, so I don't totally understand the issue. Any help would be great. Here is the code that I wrote
func makeNodes(ctx context.Context, wg *sync.WaitGroup, ch chan Node) {
defer wg.Done()
for i := 0; i < 9; i {
tmp := Node{Data: i, Next: nil}
ch <- tmp
}
<-ctx.Done()
return
}
type Node struct {
Data int
Next *Node
}
type List struct {
Head *Node
Length int
Last *Node
}
func (l *List) addToEnd(n *Node) {
if l.Head == nil {
l.Head = n
l.Last = n
l.Length
return
}
tmp := l.Last
tmp.Next = n
l.Last = n
l.Length
}
func (l List) print() {
tmp := l.Head
for tmp != nil {
fmt.Println(tmp)
tmp = tmp.Next
}
fmt.Println("\n")
}
func main() {
cha := make(chan Node)
defer close(cha)
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
var wg sync.WaitGroup
wg.Add(1)
list := List{nil, 0, nil}
go makeNodes(ctx, &wg, cha)
go func() {
for j := range cha {
list.addToEnd(&j)
}
}()
cancel()
wg.Wait()
list.print()
}
CodePudding user response:
This program allocates a single structure (j
in the for j:= range
loop) and repeatedly overwrites it with the contents read from the channel.
This results in the same variable (j
, at a fixed memory location) being added to the list multiple times.
Consider modifying the channel to be a channel of pointers.
In main()
cha := make(chan *Node)
Then for makeNodes()
Each time a new node is created (via Node{}
), a new Node pointer is placed into the channel.
func makeNodes(ctx context.Context, wg *sync.WaitGroup, ch chan *Node) {
defer wg.Done()
for i := 0; i < 9; i {
tmp := Node{Data: i, Next: nil}
ch <- &tmp
}
<-ctx.Done()
return
}
The following will now correctly add each unique Node pointer to the list.
go func() {
for j := range cha {
list.addToEnd(j)
}
}()
Also, you may find not all entities make it to the list or are read from the channel. Your method for synchronizing the producer (makeNodes()
) and consume (for j:= range
) needs work.