internal/thread: remove Stop and use context.Context instead

This commit is contained in:
Hajime Hoshi 2022-12-28 17:03:49 +09:00
parent 01eb1a0bca
commit c638727759
3 changed files with 38 additions and 28 deletions

View File

@ -14,18 +14,20 @@
package thread package thread
import (
"context"
)
// Thread defines threading behavior in Ebitengine. // Thread defines threading behavior in Ebitengine.
type Thread interface { type Thread interface {
Call(func()) Call(func())
Loop() Loop(context.Context) error
Stop()
} }
// OSThread represents an OS thread. // OSThread represents an OS thread.
type OSThread struct { type OSThread struct {
funcs chan func() funcs chan func()
done chan struct{} done chan struct{}
terminate chan struct{}
} }
// NewOSThread creates a new thread. // NewOSThread creates a new thread.
@ -33,7 +35,6 @@ func NewOSThread() *OSThread {
return &OSThread{ return &OSThread{
funcs: make(chan func()), funcs: make(chan func()),
done: make(chan struct{}), done: make(chan struct{}),
terminate: make(chan struct{}),
} }
} }
@ -42,7 +43,7 @@ func NewOSThread() *OSThread {
// It is assumed that an OS thread is fixed by runtime.LockOSThread when Loop is called. // It is assumed that an OS thread is fixed by runtime.LockOSThread when Loop is called.
// //
// Loop must be called on the thread. // Loop must be called on the thread.
func (t *OSThread) Loop() { func (t *OSThread) Loop(ctx context.Context) error {
for { for {
select { select {
case fn := <-t.funcs: case fn := <-t.funcs:
@ -53,17 +54,12 @@ func (t *OSThread) Loop() {
fn() fn()
}() }()
case <-t.terminate: case <-ctx.Done():
return return ctx.Err()
} }
} }
} }
// Stop stops the thread loop.
func (t *OSThread) Stop() {
t.terminate <- struct{}{}
}
// Call calls f on the thread. // Call calls f on the thread.
// //
// Do not call this from the same thread. This would block forever. // Do not call this from the same thread. This would block forever.
@ -83,10 +79,9 @@ func NewNoopThread() *NoopThread {
} }
// Loop does nothing // Loop does nothing
func (t *NoopThread) Loop() {} func (t *NoopThread) Loop(ctx context.Context) error {
return nil
}
// Call executes the func immediately // Call executes the func immediately
func (t *NoopThread) Call(f func()) { f() } func (t *NoopThread) Call(f func()) { f() }
// Stop does nothing
func (t *NoopThread) Stop() {}

View File

@ -17,6 +17,9 @@
package ui package ui
import ( import (
stdcontext "context"
"errors"
"github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand"
"github.com/hajimehoshi/ebiten/v2/internal/thread" "github.com/hajimehoshi/ebiten/v2/internal/thread"
) )
@ -36,21 +39,26 @@ func (u *userInterfaceImpl) Run(game Game, options *RunOptions) error {
return err return err
} }
ctx, cancel := stdcontext.WithCancel(stdcontext.Background())
defer cancel()
ch := make(chan error, 1) ch := make(chan error, 1)
go func() { go func() {
defer close(ch) defer close(ch)
if err := u.loopGame(); err != nil { if err := u.loopGame(); err != nil {
ch <- err ch <- err
cancel()
return return
} }
}() }()
defer u.mainThread.Stop() err := u.mainThread.Loop(ctx)
u.mainThread.Loop() if errors.Is(err, stdcontext.Canceled) {
return <-ch return <-ch
} }
return err
}
// runOnAnotherThreadFromMainThread is called from the main thread, and calls f on a new goroutine (thread). // runOnAnotherThreadFromMainThread is called from the main thread, and calls f on a new goroutine (thread).
// runOnAnotherThreadFromMainThread creates a new nested main thread and runs the run loop. // runOnAnotherThreadFromMainThread creates a new nested main thread and runs the run loop.
@ -68,9 +76,11 @@ func (u *userInterfaceImpl) runOnAnotherThreadFromMainThread(f func()) {
u.mainThread = thread.NewOSThread() u.mainThread = thread.NewOSThread()
graphicscommand.SetRenderingThread(u.mainThread) graphicscommand.SetRenderingThread(u.mainThread)
ctx, cancel := stdcontext.WithCancel(stdcontext.Background())
defer cancel()
go func() { go func() {
defer u.mainThread.Stop() defer cancel()
f() f()
}() }()
u.mainThread.Loop() _ = u.mainThread.Loop(ctx)
} }

View File

@ -17,6 +17,7 @@
package ui package ui
import ( import (
stdcontext "context"
"fmt" "fmt"
"runtime/debug" "runtime/debug"
"sync" "sync"
@ -80,12 +81,16 @@ func (u *userInterfaceImpl) Update() error {
return err return err
} }
ctx, cancel := stdcontext.WithCancel(stdcontext.Background())
defer cancel()
renderCh <- struct{}{} renderCh <- struct{}{}
go func() { go func() {
<-renderEndCh <-renderEndCh
u.t.Stop() cancel()
}() }()
u.t.Loop()
_ = u.t.Loop(ctx)
return nil return nil
} }