2017-07-02 69 views
1

我正在製作Go的控制檯音樂播放器。每當用戶選擇和播放一張專輯,我推出的goroutine在播放列表。不止一次取消context.Context?

playlist := make([]*Media, 0) 
for _, path := range album.Paths { 
    media, err := NewMediaFromPath(path) 
    // return err 

    playlist = append(playlist, media) 
} 

for idx := range playlist { 
    player.SetMedia(playlist[idx]) 
    err = player.Play() 
    // check err 

    status, err := player.MediaState() 
    // check err 

    for status != MediaEnded && status != MediaStopped { 
     // update UI and check player status 
     // loop until the song finishes 
     status, err = player.MediaState() 
    } 
} 

我需要的的方式取消此夠程,當用戶選擇新專輯。我使用context.Context這樣做(但我不相信這是最好的解決方案)。

我創建ctx

ctx, cancel := context.WithCancel(context.Background()) 

所以在UI事件處理程序,該play()funccancel()的夠程。

只能用一次我檢查更新UI內for循環:

 select { 
     case <-ctx.Done(): 
      return err 
     default: 
      time.Sleep(50 * time.Millisecond) 
     } 

則通道​​關閉並播放下一個專輯總會返回,而不是循環。

有沒有辦法來recancel一個context.Context

如果沒有,有沒有更好的辦法來取消這個夠程(及以下夠程)?

或者我試着使用waitgroups,

go func() { 
     wg.Wait() 
     wg.Add(1) 
     err = playAlbum(
      done, 
      player, 
      *albums[s], 
      list, 
      status, 
     ) 
     wg.Done() 
     // handle err 
    }() 

但後來我得到一個恐慌

回答

1

有關使用一個通道取消夠程什麼?

select { 
case <-chClose: 
    return 
default: 
} 

你的取消()調用可以簡單地關閉通道:

close(chClose) 

但你不能再收吧!所以你需要確保你的新專輯有一個新的chClose。根據你的代碼結構,這可能是更乾淨的解決方案。

或者你可以只發送上chClose的值來啓動走程序的停止:

chClose <- 1 

你可以做到這一點往往你想要的。

需要注意的是,如果沒有夠程聽,這將阻止(或如果你有一個緩衝區,你最終會關閉該甚至還沒有startet尚未程序 - >你需要一個乾淨的架構!!)