如果goroutine正在运行,则停止它
我有一个类似于How to stop a goroutine with a small twist的问题。我不确定 goroutine 是否正在运行。
var quit = make(chan bool)
func f1() {
go func() {
t := time.NewTimer(time.Minute)
select {
case <-t.C:
// Do stuff
case <-quit:
return
}
}()
}
func f2() {
quit <- true
}
如果f2()在 之后不到一分钟被调用f1(),则 goroutine 返回。但是,如果它在一分钟后被调用,goroutine 将已经返回并f2()会阻塞。f2()如果 goroutine 正在运行,我想取消它,否则什么都不做。
我在这里试图实现的是当且仅当它在创建后的一分钟内没有被取消时才执行任务。
说明:
- 没有什么可以阻止
f2()被多次调用的。 - 一次只有一个 goroutine 在运行。的调用者
f1()将确保每分钟调用它的次数不会超过一次。
回答
使用上下文。
f1使用可能被取消的上下文运行。运行f2与相关的取消功能。
func f1(ctx context.Context) {
go func(ctx context.Context) {
t := time.NewTimer(time.Minute)
select {
case <-t.C:
// Do stuff
case <-ctx.Done():
return
}
}(ctx)
}
func f2(cancel context.CancelFunc) {
cancel()
}
稍后,为了协调这两个功能,您将执行以下操作:
ctx, cancel := context.WithCancel(context.Background())
f1(ctx)
f2(cancel)
您还可以尝试使用该context.WithTimeout函数来合并外部定义的超时。
如果你不知道是否有一个 goroutine 已经在运行,你可以像上面一样初始化ctx和cancel变量,但不要将它们传递给任何东西。这避免了必须检查nil.
请记住将 ctx 和 cancel 视为要复制的变量,而不是引用,因为您不希望多个 goroutine 共享内存 - 这可能会导致竞争条件。
- You should create a new context, otherwise it may have already been cancelled.