Home > OS >  Concurrently Add Nodes to Linked List golang
Concurrently Add Nodes to Linked List golang

Time:06-28

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.

  • Related