mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-17 18:40:33 +00:00
feature(WorkerThread): Tick() returns bool to allow the thread function to stop the thread gracefully
This commit is contained in:
parent
1e94e12150
commit
927bdccf6e
@ -21,8 +21,10 @@ public class WorkerThread
|
||||
// callbacks need to be set after constructor.
|
||||
// inheriting classes can't pass their member funcs to base ctor.
|
||||
// don't set them while the thread is running!
|
||||
// -> Tick() returns a bool so it can easily stop the thread
|
||||
// without needing to throw InterruptExceptions or similar.
|
||||
public Action Init;
|
||||
public Action Tick;
|
||||
public Func<bool> Tick;
|
||||
public Action Cleanup;
|
||||
|
||||
public WorkerThread(string identifier)
|
||||
@ -104,7 +106,7 @@ public bool StopBlocking(float timeout)
|
||||
// always define them, and make them call actions.
|
||||
// those can be set at any time.
|
||||
void OnInit() => Init?.Invoke();
|
||||
void OnTick() => Tick?.Invoke();
|
||||
bool OnTick() => Tick?.Invoke() ?? false;
|
||||
void OnCleanup() => Cleanup?.Invoke();
|
||||
|
||||
// guarded wrapper for thread code.
|
||||
@ -128,7 +130,9 @@ public void Guard(string identifier)
|
||||
// run thread func while active
|
||||
while (active)
|
||||
{
|
||||
OnTick();
|
||||
// Tick() returns a bool so it can easily stop the thread
|
||||
// without needing to throw InterruptExceptions or similar.
|
||||
if (!OnTick()) break;
|
||||
}
|
||||
}
|
||||
// Thread.Interrupt() will gracefully raise a InterruptedException.
|
||||
|
@ -35,7 +35,7 @@ public void Callbacks()
|
||||
int tickCalled = 0;
|
||||
int cleanupCalled = 0;
|
||||
void Init() => Interlocked.Increment(ref initCalled);
|
||||
void Tick() => Interlocked.Increment(ref tickCalled);
|
||||
bool Tick() { Interlocked.Increment(ref tickCalled); return true; }
|
||||
void Cleanup() => Interlocked.Increment(ref cleanupCalled);
|
||||
|
||||
// ctor runs thread and calls callback immediately
|
||||
@ -82,7 +82,7 @@ public void ExceptionInTick()
|
||||
// exceptions in threads are silent by default.
|
||||
// guarantee we try/catch them.
|
||||
int cleanupCalled = 0;
|
||||
void Tick() => throw new Exception("Test Exception");
|
||||
bool Tick() => throw new Exception("Test Exception");
|
||||
void Cleanup() => Interlocked.Increment(ref cleanupCalled);
|
||||
|
||||
// ctor runs thread and calls callback immediately
|
||||
@ -103,6 +103,7 @@ public void IsAlive()
|
||||
{
|
||||
thread = new WorkerThread("WorkerThreadTests");
|
||||
Assert.False(thread.IsAlive);
|
||||
thread.Tick = () => true;
|
||||
thread.Start();
|
||||
|
||||
Thread.Sleep(10);
|
||||
@ -111,13 +112,26 @@ public void IsAlive()
|
||||
Assert.False(thread.IsAlive);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TickIndicatesEnd()
|
||||
{
|
||||
thread = new WorkerThread("WorkerThreadTests");
|
||||
Assert.False(thread.IsAlive);
|
||||
// returning false should automatically stop the thread
|
||||
thread.Tick = () => false;
|
||||
thread.Start();
|
||||
|
||||
Thread.Sleep(10);
|
||||
Assert.False(thread.IsAlive);
|
||||
}
|
||||
|
||||
// make sure stop returns immediately, but does stop it eventually
|
||||
[Test]
|
||||
public void SignalStop()
|
||||
{
|
||||
thread = new WorkerThread("WorkerThreadTests");
|
||||
Assert.False(thread.IsAlive);
|
||||
thread.Tick = () => Thread.Sleep(50);
|
||||
thread.Tick = () => { Thread.Sleep(50); return true; };
|
||||
thread.Start();
|
||||
|
||||
// stop should return immediately, while thread is shutting down
|
||||
@ -135,7 +149,7 @@ public void StopBlocking()
|
||||
{
|
||||
thread = new WorkerThread("WorkerThreadTests");
|
||||
Assert.False(thread.IsAlive);
|
||||
thread.Tick = () => Thread.Sleep(50);
|
||||
thread.Tick = () => { Thread.Sleep(50); return true; };
|
||||
thread.Start();
|
||||
|
||||
// stop should wait until fully stopped
|
||||
@ -149,7 +163,7 @@ public void StopBlocking_Deadlocked()
|
||||
{
|
||||
thread = new WorkerThread("WorkerThreadTests");
|
||||
Assert.That(thread.IsAlive, Is.False);
|
||||
thread.Tick = () => Thread.Sleep(5000);
|
||||
thread.Tick = () => { Thread.Sleep(5000); return true; };
|
||||
thread.Start();
|
||||
|
||||
// wait for it to start
|
||||
|
@ -263,7 +263,9 @@ void ProcessThreadQueue()
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadTick()
|
||||
// Tick() returns a bool so it can easily stop the thread
|
||||
// without needing to throw InterruptExceptions or similar.
|
||||
bool ThreadTick()
|
||||
{
|
||||
// early update the implementation first
|
||||
ThreadedClientEarlyUpdate();
|
||||
@ -279,6 +281,7 @@ void ThreadTick()
|
||||
// save some cpu power.
|
||||
// TODO update interval and sleep extra time would be ideal
|
||||
Thread.Sleep(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// threaded callbacks to call from transport thread.
|
||||
|
Loading…
Reference in New Issue
Block a user