Home  >  Article  >  Backend Development  >  Stop a goroutine that writes to a channel indefinitely

Stop a goroutine that writes to a channel indefinitely

WBOY
WBOYforward
2024-02-05 23:09:07901browse

停止无限期写入通道的 goroutine

Question content

I have a function that creates a goroutine that fills a channel indefinitely, for example:

func foo() <-chan int {
  ch := make(chan int) 
  go func() {
    defer close(ch)
    for {
      ch <- 1
    } 
  }() 
  return ch
}

Suppose we have a consumer that we want to stop after a period of time:

ch:=foo() 
<-ch
<-ch
// done

Now I want to clean up goroutine resources, including channels. I tried adding a "completion" channel for this, but then I ran into a deadlock:

func Foo() (<-chan int, chan<- bool) {
  ch := make(chan int)
  done := make(chan bool)
  go func() {
    defer close(ch)
    for {
      select {
      case <-done:
          return
      default:
          ch <- 1
      }
    } 
  }() 
  return ch, done
}

func main() {
  ch, done := Foo()
  <-ch
  <-ch
  done <- true
  // HERE
}

Now, it seems to work, but that's only because the program exits, if I replace // here with some io operations (for example: http.get("http://google. com")), I'm facing a deadlock (fatal error: all goroutines are sleeping - deadlock!). I'm wondering if there is another way to clean up the generated goroutines and channels created by the foo function.


Correct answer


Just replace default with case in the started goroutine:

func Foo() (<-chan int, chan<- bool) {
  ch := make(chan int)
  done := make(chan bool)
  go func() {
    defer close(ch)
    for {
      select {
      case <-done:
          return
      case ch <- 1:
      }
    } 
  }() 
  return ch, done
}

The reasons why the original code deadlocked in the default situation are as follows:

  • When no other concurrently running goroutines write to the done channel, goroutines initiated to write to the ch channel will immediately go to the default case. The goroutine will then block on line ch <- 1 until another goroutine reads the value from ch.
  • The main coroutine reads twice from ch. This results in two successful execution loops at the launched goroutine. It then tries to write done. The goroutine started at this time may have checked the select statement, fell into the default situation and blocked at the ch <- 1 line. Therefore the main goroutine will also block indefinitely on the done <- true line. This can lead to a deadlock.

The above is the detailed content of Stop a goroutine that writes to a channel indefinitely. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete