1 Star 0 Fork 0

h79/goutils

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
run.go 5.55 KB
一键复制 编辑 原始数据 按行查看 历史
huqiuyun 提交于 2024-03-16 20:05 . delay time
package system
import (
"context"
"errors"
"fmt"
"os"
"os/signal"
"sync"
"sync/atomic"
"syscall"
"time"
)
var closeCh chan bool
var quited bool
var quitErr error
var quitCode int32
var ErrNormalQuit = errors.New("normal quit")
func init() {
var _ = closeCh
var _ = quited
closeCh = make(chan bool)
quited = false
}
type ExitSig struct {
S chan os.Signal
}
func (c *ExitSig) Done() <-chan os.Signal {
return c.S
}
func Exit() *ExitSig {
e := &ExitSig{S: make(chan os.Signal)}
signal.Notify(e.S, os.Interrupt, os.Kill, syscall.SIGTERM, syscall.SIGQUIT)
return e
}
func IsNormalQuit() bool {
return quited && (quitErr == nil || errors.Is(ErrNormalQuit, quitErr))
}
func IsQuit() bool {
return quited
}
func GetQuitCode() int32 {
return quitCode
}
func SetQuitCode(code int32) {
quitCode = code
}
func GetQuitErr() error {
return quitErr
}
func SetQuitErr(err error) {
quitErr = err
}
func QuitApp(code int32) {
if quited {
return
}
quited = true
quitCode = code
close(closeCh)
fmt.Println("quit program.")
}
func Close() {
QuitApp(-1)
}
func Closed() <-chan bool {
return closeCh
}
func AfterQuit(t time.Duration) {
Wait(t)
}
func Wait(t time.Duration) {
timeout := time.After(t)
select {
case <-timeout:
return
}
}
func Stop(d time.Duration, stop chan bool) {
go func() {
Wait(d)
var t = time.After(d * 2)
select {
case <-stop:
stop <- true
return
case <-t:
return
}
}()
stop <- true
<-stop
}
type Running struct {
ev *Event
c int32
wg sync.WaitGroup
}
var (
mainIf int32 = 0
running *Running
once sync.Once
)
func Go() *Running {
once.Do(func() {
running = NewRunning()
})
return running
}
// NewRunning
// f 是否fire
func NewRunning() *Running {
return &Running{ev: NewEvent()}
}
func ChildRunning(fn func(), exits ...func()) {
Go().Run(false, fn, exits...)
}
func MainRunning(fn func(), exits ...func()) {
if atomic.AddInt32(&mainIf, 1) > 1 {
panic("can not repeat call,only call one")
}
Go().runM(fn, exits...)
}
// Run if fire=true, select Running.Done()
func (m *Running) Run(fire bool, fn func(), exits ...func()) {
if quited {
return
}
var c = atomic.AddInt32(&m.c, 1)
fmt.Println("enter child go coroutine,count: ", c)
m.wg.Add(1)
go func() {
defer m.done(true, fire)
defer Recover(exits...)
fn()
}()
}
func (m *Running) runM(fn func(), exits ...func()) {
if quited {
return
}
var c = atomic.AddInt32(&m.c, 1)
fmt.Println("enter main go coroutine,count: ", c)
m.wg.Add(1)
go func() {
defer m.done(false, true)
defer Recover(exits...)
defer Close()
defer atomic.StoreInt32(&mainIf, 0)
fn()
}()
}
func (m *Running) done(child, fire bool) {
var c = atomic.AddInt32(&m.c, -1)
fmt.Println("exit go coroutine, count: ", c, ",it is main coroutine: ", !child)
if fire {
m.ev.Fire()
}
m.wg.Done()
}
func (m *Running) Done() <-chan struct{} {
return m.ev.Done()
}
func (m *Running) Wait() {
m.wg.Wait()
}
func (m *Running) Count() int32 {
return atomic.LoadInt32(&m.c)
}
type RunningCheck struct {
rm sync.RWMutex
fRun bool
}
func (rc *RunningCheck) IsRunning() bool {
rc.rm.RLock()
defer rc.rm.RUnlock()
return rc.fRun
}
// Deprecated: this function simply calls [GoRunning].
func (rc *RunningCheck) TryGoRunning(fn func(), exits ...func()) {
rc.GoRunning(fn, exits...)
}
func (rc *RunningCheck) GoRunning(fn func(), exits ...func()) {
rc.GoRunningV2(func() {}, fn, exits...)
}
func (rc *RunningCheck) GoRunningV2(running func(), fn func(), exits ...func()) {
if rc.IsRunning() {
return
}
rc.runningSet(true)
running()
ChildRunning(func() {
defer rc.runningSet(false)
fn()
}, exits...)
}
func (rc *RunningCheck) runningSet(flag bool) {
rc.rm.Lock()
rc.fRun = flag
rc.rm.Unlock()
}
type Task func() (any, error)
type Ctrl struct {
}
func NewCtrl() *Ctrl {
return &Ctrl{}
}
func (c *Ctrl) RunAfter(timeout time.Duration, task Task) (any, error) {
if timeout <= 0 {
return task()
}
resultCh := make(chan *resultWithError, 1)
ChildRunning(func() {
result, err := task()
resultCh <- &resultWithError{result, err}
})
select {
case <-time.After(timeout):
return nil, TimeoutError
case rwe := <-resultCh:
return rwe.result, rwe.err
case <-Closed():
return nil, ClosedError
}
}
func (c *Ctrl) RunWithContext(ctx context.Context, task Task) (any, error) {
resultCh := make(chan *resultWithError, 1)
ChildRunning(func() {
result, err := task()
resultCh <- &resultWithError{result, err}
})
select {
case <-ctx.Done():
return nil, ctx.Err()
case rwe := <-resultCh:
return rwe.result, rwe.err
case <-Closed():
return nil, ClosedError
}
}
// Ticker
// 定时调用
func (c *Ctrl) Ticker(tick time.Duration, fun func(any) bool, param any, funcDefer func(any) bool, paramDefer any) {
c.Delay(0, tick, fun, param, funcDefer, paramDefer)
}
func (c *Ctrl) DelayOnly(delay time.Duration, fun func(any) bool, param any, funcDefer func(any) bool, paramDefer any) {
c.Delay(delay, 0, fun, param, funcDefer, paramDefer)
}
func (c *Ctrl) Delay(delay, tick time.Duration, fun func(any) bool, param any, funcDefer func(any) bool, paramDefer any) {
if fun == nil {
panic("fun is nil")
}
ChildRunning(func() {
defer func() {
if funcDefer != nil {
funcDefer(paramDefer)
}
}()
if delay > 0 {
Wait(delay)
}
if tick <= 0 {
fun(param)
return
}
if delay > 0 {
if fun(param) {
return
}
}
ticker := time.NewTicker(tick)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if fun(param) {
return
}
case <-Closed():
return
}
}
})
}
type resultWithError struct {
result any
err error
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/h79/goutils.git
git@gitee.com:h79/goutils.git
h79
goutils
goutils
v1.20.114

搜索帮助