即使使用 WaitGroup 同步,Goroutine 已启动但未执行或部分执行

标签 go synchronization channel goroutine

我在使用通过 channel 从另一个goroutine接收的数据同时启动多个goroutines来反向链表时遇到了一个奇怪的问题,这困扰了我很多天,我只想将列表拆分成几个子列表而不断开链接然后分别启动 goroutine 来反转它,但是在运行代码时我总是得到如下输出所示的运行时错误,我真的不知道如何在我尝试了很多更改之后修复它但仍然得到相同的错误,有人可以指出问题或给我建议?欢迎并感谢您提供的任何帮助,如果您能提供改进的代码,那就太好了,在此先感谢!

更新:问题是由于数据竞争导致内存损坏,已通过读写锁解决!

这是我的代码:

package main

import "sync"

type node struct {
    data int
    next *node
}

type LinkedList struct {
    head *node
    size int
}

type splitResult struct {
    beforeHead, head, tail *node
}

func splitList(head *node, sizoflst, sizofsublst int) <-chan *splitResult {
    nGoroutines := sizoflst / sizofsublst
    if sizoflst < sizofsublst {
        nGoroutines++
    } else {
        if (sizoflst % sizofsublst) >= 6 {
            nGoroutines++
        }
    }
    ch := make(chan *splitResult, nGoroutines)
    go func() {
        defer close(ch)
        var beforeHead *node
        tail := head
        ct := 0
        for i := 0; i < nGoroutines; i++ {
            for ct < sizofsublst-1 && tail.next != nil {
                tail = tail.next
                ct++
            }
            if i == nGoroutines-1 {
                testTail := tail
                for testTail.next != nil {
                    testTail = testTail.next
                }
                ch <- &splitResult{beforeHead, head, testTail}
                break
            }
            ch <- &splitResult{beforeHead, head, tail}
            beforeHead = tail
            head = tail.next
            tail = head
            ct = 0
        }
    }()
    return ch
}

func reverse(split *splitResult, ln **node, wg *sync.WaitGroup) {
    defer wg.Done()
    move := split.head
    prev := split.beforeHead
    if split.tail.next == nil {
        *ln = split.tail
    }
    for move != split.tail.next {
        temp := move.next
        move.next = prev
        prev = move
        move = temp
    }
}

func (ll *LinkedList) Reverse(sizofsublst int) {
    var lastNode *node
    var wg sync.WaitGroup
    if ll.head == nil || ll.head.next == nil {
        return
    }
    splitCh := splitList(ll.head, ll.size, sizofsublst)
    for split := range splitCh {
        wg.Add(1)
        go reverse(split, &lastNode, &wg)
    }
    wg.Wait()
    ll.head = lastNode
}

func (ll *LinkedList) Insert(data int) {
    newNode := new(node)
    newNode.data = data
    newNode.next = ll.head
    ll.head = newNode
    ll.size++
}

func main() {
    ll := &LinkedList{}
    sli := []int{19, 30, 7, 23, 24, 0, 12, 28, 3, 11, 18, 1, 31, 14, 21, 2, 9, 16, 4, 26, 10, 25}
    for _, v := range sli {
        ll.Insert(v)
    }
    ll.Reverse(8)
}

输出:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x458db5]

goroutine 21 [running]:
main.reverse(0xc4200820a0, 0xc420096000, 0xc420098000)
        /home/user/go/src/local/stackoverflow/tmp.go:69 +0x75
created by main.(*LinkedList).Reverse
        /home/user/go/src/local/stackoverflow/tmp.go:85 +0x104

最佳答案

我认为您的问题只是为 Nil 赋值。不要在每个地方都分配一个 Nil 指针。

Code Here

关于即使使用 WaitGroup 同步,Goroutine 已启动但未执行或部分执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50524859/

相关文章:

google-app-engine - App Engine 转到 : How to kill a running goroutine

go - 在同一个包中调用函数和变量,但使用构建标签调用不同的文件

javascript - 在 Nodejs 中处理异步

multithreading - 如果主线程完成,我是否必须向匿名线程发出退出信号?

go - 想要使用 channel 从 os.Stdin 写入 os.Stdout

go - 在选择中支持一种通信(chan)

json - Golang post 返回 json 响应

C#按时间同步2个不同类型的列表

python - Django Websockets 数据转到错误的套接字

java - 未过期的谷歌日历api channel java