Waiting and deadlock usage of golang coroutine

Time:2021-10-10

Direct code:

1. The first case

If there is no select {}, the main thread will not wait for coroutine to run, resulting in no chance for coroutine to run.

You are requesting eventual scheduling (using the two go statements)

of two goroutines and then you exit main without giving the scheduler

a chance to do anything.

With select, the program runs normally.


package main
import (
 "fmt"
        "time"
)
func main() {
 go func1()
 go func2()
 select{}
}
func func1() {
       for{
     fmt.Println("here1")
            time.Sleep(10 * time.Minute)
        }
}
func func2() {
       for{
    fmt.Println("here2")
           time.Sleep(10 * time.Minute)
       }
}

2. Coroutine has the opportunity to run

But deadlocks occur. Fatal error: all goroutines are asleep – deadlock!

The goroutine executing func1 exited, ditto for func2. The main goroutine is blocked with no hope to recover while no other goroutine can be scheduled.


package main
import (
 "fmt"
 //"time"
)
func main() {
 go func1()
 go func2()
 select {
 }
}
func func1() {
 fmt.Println("here1")
}
func func2() {
 fmt.Println("here2")
}

3. The third case is normal operation


package main
import (
 "fmt"
)
var c = make(chan int, 2)
func main() {
 go func1()
 go func2()
 <-c
 <-c
 fmt.Println("ok")
}
func func1() {
 fmt.Println("here1")
 c <- 1
}
func func2() {
 fmt.Println("here2")
 c <- 1
}

4. Another way to achieve the above purpose:


  var wg sync.WaitGroup
    var urls = []string{
            "http://www.golang.org/",
            "http://www.google.com/",
            "http://www.somestupidname.com/",
    }
    for _, url := range urls {
            // Increment the WaitGroup counter.
            wg.Add(1)
            // Launch a goroutine to fetch the URL.
            go func(url string) {
                    // Decrement the counter when the goroutine completes.
                    defer wg.Done()
                    // Fetch the URL.
                    http.Get(url)
            }(url)
    }
    // Wait for all HTTP fetches to complete.
    wg.Wait()

Supplement: deadlock analysis in golang

Golang’s summary of channel deadlock and Solutions

Read deadlock of empty channel directly

Deadlock occurs when there is no data in a channel and it is read directly:


func main() {
    q := make(chan int, 2)
    <-q
}

Error message:

fatal error: all goroutines are asleep – deadlock!

goroutine 1 [chan receive]:

main.main()

/home/erick/Desktop/Book/Parallel/final.go:159 +0x4d

exit status 2

In the above code, a 2-capacity channel is created, and a deadlock occurs in direct reading.

Fix the scheme, use the select method to block, and place the default processing method in the default:


func main() {
    q := make(chan int, 2)
    select {
    case v := <-q:
        fmt.Println(v)
    default:
        fmt.Println("nothing in channel")
    }
}

Output:

nothing in channel

Deadlock caused by over writing data

If the written data exceeds the capacity of the channel, it will also cause deadlock:


func main() {
    q := make(chan int, 2)
    q <- 1
    q <- 2
    q <- 3
}

The solution is the same as the writing method. Use the select method to block and place the default processing method in the default:


func main() {
    q := make(chan int, 2)
    q <- 1
    q <- 2
    select {
    case q <- 3:
        fmt.Println("ok")
    default:
        fmt.Println("wrong")
    }
}

Write data to closed channels

This is not a deadlock, but a panic.


func main() {
    q := make(chan int, 2)
    close(q)
    q <- 1
}

Code error:

panic: send on closed channel

goroutine 1 [running]:

main.main()

/home/erick/Desktop/Book/Parallel/final.go:154 +0x63

exit status 2

Solution: only do not write data to the closed channel….

However, data can be read from closed channels:


func main() {
    q := make(chan int, 3)
    q <- 1
    q <- 2
    q <- 3
    close(q)
    for v := range q {
        fmt.Println(v)
    }

Let’s begin to explain the reading and writing of goroutine


package main
import "fmt"
func main() {
 c:=make(chan string)
 go func() {
  c<-"hello"
 }()
 fmt.Println(<-c)
}

The one above is right


package main
import "fmt"
func main() {
 c:=make(chan string)
 fmt.Println(<-c)
 go func() {
  c<-"hello"
 }()
}

The above is wrong. A deadlock will occur because the program will block in FMT. Println (< – C) and will not execute downward. A block occurred on this line so that the following code had no chance to execute. Therefore, it can be summarized that there is no read operation until the write operation is completed.

Summary:

The deadlock mentioned above refers to the situation that occurs in the main thread of the program. If the above situation occurs in a non main thread, the reading or writing situation is blocked, not a deadlock.

In fact, the blocking situation eliminates the steps of locking. Instead, it is more conducive to code writing. We should make rational use of blocking..

The above is my personal experience. I hope I can give you a reference, and I hope you can support developpaer. If you have any mistakes or don’t consider completely, please don’t hesitate to comment.

Recommended Today

Mybatis finishing

Mybatis framework and principle analysis Mybatis is an excellent persistence layer framework that supports customized SQL, stored procedures and advanced mapping. It mainly completes two things: Encapsulating JDBC operations Use reflection to get through the mutual conversion between Java classes and SQL statements The main design purpose of mybatis is to make it more convenient […]