I ran into a weird problem when using data received through channel from another goroutine to start multiple goroutines to reverse linked list simultaneously, which has troubled me for many days, I just want to split list into a couple of sublist without break link and then respectively start goroutine to reverse it, but I always get runtime error as below output shows when running code, I really don't know how to fix it after I tried many changes but still got the same error, can someone point out the problem or give me advice? any help you can give is welcome and appreciated, It would be nice if you can provide improved code, thanks in advance!
UPDATE: the problem was caused by memory corruption due to data race, it has been solved by using read-write lock!
Here is my code:
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)
}
output:
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