Smbsg
Smbsg

Reputation: 41

Getting panic for running goroutines even with mutex locking and defer

**func (p *linkedList) showalldoctorsrecursive() error {
    defer wg.Done()
    mutex.Lock()
    {
        if p.head != nil {
            printRecursiveF(p.head)
        } else {
            fmt.Println("The list is empty.")
        }
    }
    mutex.Unlock()
    return nil
}
func (p *linkedList) showalldoctorsfront() error {
    defer wg.Done()
    mutex.Lock()
    {
        if p.head != nil {
            printfront(p.head)
        } else {
            fmt.Println("The list is empty.")
        }
    }
    mutex.Unlock()
    return nil
}
func printRecursiveF(n *Node2) {
    if n != nil {
        printRecursiveF(n.next)
        fmt.Println(n.item, n.next.time)
    }
}
func printfront(n *Node2) {
    if n != nil {
        fmt.Println(n.item)
        fmt.Println(n.item, n.next.time)
    }
}**

func (p *queue) displayallpatients() error {
    defer wg.Done()
    mutex.Lock()
    {
        currentNode := p.front
        if currentNode == nil {
            fmt.Println("There are no patients.")
            return nil
        }
        fmt.Println("Displaying all patients and their appointment times")
        fmt.Println(currentNode.item, currentNode.time)
        for currentNode.next != nil {
            currentNode = currentNode.next
            fmt.Println(currentNode.item, currentNode.time)
        }
    }
    mutex.Unlock()
    return nil
}

func main() {
    var num, num1, num2 int
    runtime.GOMAXPROCS(2)
    wg.Add(3)
    myList := &linkedList{nil, 0}
    myQueue := &queue{nil, nil, 0}
    for {
        fmt.Println("Please enter 1 to check for patient or 2 to check for doctor.Alternatively,enter 3 to exit menu")
        fmt.Scanln(&num)
        _, err := mainmenu(num)
        if err != nil {
            fmt.Println(err)
        } else if num == 3 {
            break
        } else {
            fmt.Printf("Please proceed to the main menu >")
        }

        if num == 1 {
            fmt.Println("Patient Main Menu")
            fmt.Println("1. Add Patient")
            fmt.Println("2. Remove Last Patient")
            fmt.Println("3. Update Patient Details")
            fmt.Println("4. Display All Patients")
            fmt.Println("--------------")
            fmt.Println("Please enter a number to access the menu")
            fmt.Scanln(&num1)
            _, err2 := patientmenu(num1)
            if err2 != nil {
                fmt.Println(err2)
            } else if num1 == 1 {
                myQueue.addPatient()
            } else if num1 == 2 {
                myQueue.removelastpatient()
            } else if num1 == 3 {
                myQueue.updatepatient()
            } else if num1 == 4 {
                go myQueue.displayallpatients()
            }
    }

        } else if num == 2 {
            fmt.Println("Doctor Main Menu")
            fmt.Println("1. Add Doctor")
            fmt.Println("2. Search For Doctor Thru Name")
            fmt.Println("3. Search For Doctors Thru Available Time")
            fmt.Println("4. Update Doctor Details")
            fmt.Println("5. Display All Doctors(Recursive)")
            fmt.Println("6. Display All Doctors")
            fmt.Println("--------------")
            fmt.Println("Please enter a number to access the menu")
            fmt.Scanln(&num2)
            _, err3 := doctormenu(num2)
            if err3 != nil {
                fmt.Println(err3)
            } else if num2 == 1 {
                myList.addDoctors()
            } else if num2 == 2 {
                myList.searchdoctor()
            } else if num2 == 3 {
                myList.searchdoctortiming()
            } else if num2 == 4 {
                myList.updatedoctor()
            } else if num2 == 5 {
                go myList.showalldoctorsrecursive()
            } else if num2 == 6 {
                go myList.showalldoctorsfront()
            }
        }
    }
    wg.Wait()
}
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0x89ec50)
        c:/go/src/runtime/sema.go:56 +0x49
sync.(*WaitGroup).Wait(0x89ec48)
        c:/go/src/sync/waitgroup.go:130 +0x6b
main.main()
        C:/Projects/Go/src/xxx/main.go:145 +0xd85
exit status 2

I try to run goroutines and apply mutex locking and defer. However, I will face panic when running the goroutines. Is there a way I can solve this? I created a queue and linked list with some functions to display, enqueue(add) and dequeue(pop) and apply some concurrency to this. I know that wg.Add(n) and the n is the number of goroutines you run and you want to use mutex locking to ensure that the goroutines will run one at a time.

Upvotes: 2

Views: 896

Answers (2)

gudgl
gudgl

Reputation: 61

Use wg.Add(1) before starting a go routine.

Upvotes: 0

Sergei Karpov
Sergei Karpov

Reputation: 126

There is no mutex.Unlock() when the code executes:

if currentNode == nil {
    fmt.Println("There are no patients.")
    return nil
}

You are locking and never unlock:

func (p *queue) displayallpatients() error {
    defer wg.Done()
    mutex.Lock() // <- here we acquire a lock
    {
        currentNode := p.front
        if currentNode == nil {
            fmt.Println("There are no patients.")
            return nil // <- here we return without releasing the lock
        }
        // ...
    }
    mutex.Unlock() // <- never reach if currentNode == nil is true
    return nil
}

You can solve this either using defer or don't do early return:

func (p *queue) displayallpatients() error {
    defer wg.Done()
    defer mutex.Unlock() // <- defers the execution until the func returns (will release the lock)
    mutex.Lock()
    {
        currentNode := p.front
        if currentNode == nil {
            fmt.Println("There are no patients.")
            return nil
        }
        // ...
    }
    
    return nil
}

You can find more details in the docs

Upvotes: 2

Related Questions