func (tg *ThreadGroup) Stop() error {
	tg.bmu.Lock()
	defer tg.bmu.Unlock()
	if tg.isStopped() {
		return ErrStopped
	}
	close(tg.stopChan)
	tg.mu.Lock()
	for i := len(tg.onStopFns) - 1; i >= 0; i-- {
		tg.onStopFns[i]()
	}
	tg.onStopFns = nil
	tg.mu.Unlock()
	tg.wg.Wait()
	tg.mu.Lock()
	for i := len(tg.afterStopFns) - 1; i >= 0; i-- {
		tg.afterStopFns[i]()
	}
	tg.afterStopFns = nil
	tg.mu.Unlock()
	return nil
}
Stop will close the stop channel of the thread group, then call all 'OnStop'
functions in reverse order, then will wait until the thread group counter
reaches zero, then will call all of the 'AfterStop' functions in reverse
order. After Stop is called, most actions will return ErrStopped.
package sync
import (
	"errors"
	"sync"
)
var ErrStopped = errors.New("ThreadGroup already stopped")
type ThreadGroup struct {
	onStopFns    []func()
	afterStopFns []func()
	once     sync.Once
	stopChan chan struct{}
	bmu      sync.Mutex  
	mu       sync.Mutex  
	wg       sync.WaitGroup
}
func (tg *ThreadGroup) init() {
	tg.stopChan = make(chan struct{})
}
func (tg *ThreadGroup) isStopped() bool {
	tg.once.Do(tg.init)
	select {
	case <-tg.stopChan:
		return true
	default:
		return false
	}
}
func (tg *ThreadGroup) Add() error {
	tg.bmu.Lock()
	defer tg.bmu.Unlock()
	if tg.isStopped() {
		return ErrStopped
	}
	tg.wg.Add(1)
	return nil
}
func (tg *ThreadGroup) AfterStop(fn func()) {
	tg.mu.Lock()
	defer tg.mu.Unlock()
	if tg.isStopped() {
		fn()
		return
	}
	tg.afterStopFns = append(tg.afterStopFns, fn)
}
func (tg *ThreadGroup) OnStop(fn func()) {
	tg.mu.Lock()
	defer tg.mu.Unlock()
	if tg.isStopped() {
		fn()
		return
	}
	tg.onStopFns = append(tg.onStopFns, fn)
}
func (tg *ThreadGroup) Done() {
	tg.wg.Done()
}
func (tg *ThreadGroup) Flush() error {
	tg.bmu.Lock()
	defer tg.bmu.Unlock()
	if tg.isStopped() {
		return ErrStopped
	}
	tg.wg.Wait()
	return nil
}