Skip to content

Commit ec20cf0

Browse files
authored
Merge pull request #8 from coryleach/dev
Awaiters.WaitForBackground Fix
2 parents 7de7a4b + 000b520 commit ec20cf0

File tree

4 files changed

+38
-48
lines changed

4 files changed

+38
-48
lines changed

README.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@
44
<h1 align="center">Gameframe.Async 👋</h1>
55

66
<!-- BADGE-START -->
7-
[![Build Status](https://travis-ci.org/coryleach/UnityAsync.svg?branch=master)](https://travis-ci.org/coryleach/UnityAsync)
8-
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/d2749fdbc70f422a9d1efccb56d48bff)](https://www.codacy.com/manual/coryleach/UnityAsync?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=coryleach/UnityAsync&amp;utm_campaign=Badge_Grade)
97
![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/coryleach/UnityAsync?include_prereleases)
108
[![openupm](https://img.shields.io/npm/v/com.gameframe.async?label=openupm&amp;registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.gameframe.async/)
119
[![license](https://img.shields.io/github/license/coryleach/UnityAsync)](https://github.com/coryleach/UnityAsync/blob/master/LICENSE)
12-
1310
[![twitter](https://img.shields.io/twitter/follow/coryleach.svg?style=social)](https://twitter.com/coryleach)
1411
<!-- BADGE-END -->
1512

@@ -22,22 +19,22 @@
2219
#### Using UnityPackageManager (for Unity 2019.3 or later)
2320
Open the package manager window (menu: Window > Package Manager)<br/>
2421
Select "Add package from git URL...", fill in the pop-up with the following link:<br/>
25-
https://github.com/coryleach/UnityAsync.git#1.0.4<br/>
22+
https://github.com/coryleach/UnityAsync.git#1.0.5<br/>
2623

2724
#### Using UnityPackageManager (for Unity 2019.1 or later)
2825

2926
Find the manifest.json file in the Packages folder of your project and edit it to look like this:
3027
```js
3128
{
3229
"dependencies": {
33-
"com.gameframe.async": "https://github.com/coryleach/UnityAsync.git#1.0.4",
30+
"com.gameframe.async": "https://github.com/coryleach/UnityAsync.git#1.0.5",
3431
...
3532
},
3633
}
3734
```
3835

3936
<!-- DOC-START -->
40-
<!--
37+
<!--
4138
Changes between 'DOC START' and 'DOC END' will not be modified by readme update scripts
4239
-->
4340

@@ -95,8 +92,8 @@ await Awaiters.MainUnityThread;
9592

9693

9794
## Show your support
98-
9995
Give a ⭐️ if this project helped you!
96+
{AUTHOR.KOFI}
10097

10198
***
10299
_This README was generated with ❤️ by [Gameframe.Packages](https://github.com/coryleach/unitypackages)_

Runtime/Awaiters.cs

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Runtime.CompilerServices;
33
using System.Threading.Tasks;
4+
using UnityEngine;
45

56
namespace Gameframe.Async
67
{
@@ -9,17 +10,17 @@ public static class Awaiters
910
private static readonly WaitForBackground _waitForBackground = new WaitForBackground();
1011
private static readonly WaitForUnityThread _waitForUnityUnityThread = new WaitForUnityThread();
1112
private static readonly WaitForUpdate _waitForUpdate = new WaitForUpdate();
12-
13+
1314
/// <summary>
1415
/// Await this property to migrate an async method to a background thread
1516
/// </summary>
1617
public static WaitForBackground BackgroundThread => _waitForBackground;
17-
18+
1819
/// <summary>
1920
/// Await this property to migrate to the Unity main thread.
2021
/// </summary>
2122
public static WaitForUnityThread MainUnityThread => _waitForUnityUnityThread;
22-
23+
2324
/// <summary>
2425
/// Await this property to resume on the same context after the game has advanced a frame
2526
/// </summary>
@@ -32,35 +33,19 @@ private class BackgroundThreadJoinAwaiter : AbstractThreadJoinAwaiter
3233
{
3334
public override void OnCompleted(Action continuation)
3435
{
35-
if (isCompleted)
36-
{
37-
throw new InvalidOperationException("Continuation is invalid. This awaiter is already completed.");
38-
}
39-
_continuation = continuation;
36+
Complete();
37+
Task.Run(continuation);
4038
}
4139
}
42-
40+
4341
public IAwaitable GetAwaiter()
4442
{
45-
//Doing Task.Run(()=>{}).ConfigureAwait(false) will apparently sometimes still resume on the main thread
46-
//Updated to the below pattern to ensure we actually will be running in the background when we resume
47-
var awaiter = new BackgroundThreadJoinAwaiter();
48-
Task.Run(async () =>
49-
{
50-
//Doing complete immediately without a yield appears to cause the awaiter to never resume
51-
//I'm not entirely sure as to why.
52-
//I suspected maybe Complete() was getting called before the the method doing the awaiting could add its continuation
53-
//However when I added a check and exception for this I did not see it get thrown.
54-
//Adding the await Task.Yield however appeared to get Unit tests to consistently pass.
55-
await Task.Yield();
56-
awaiter.Complete();
57-
});
58-
return awaiter;
43+
return new BackgroundThreadJoinAwaiter();;
5944
}
6045
}
6146

6247
public class WaitForUnityThread
63-
{
48+
{
6449
private class MainThreadJoinAwaiter : AbstractThreadJoinAwaiter
6550
{
6651
public override void OnCompleted(Action continuation)
@@ -69,15 +54,15 @@ public override void OnCompleted(Action continuation)
6954

7055
}
7156
}
72-
57+
7358
public IAwaitable GetAwaiter()
7459
{
7560
var awaiter = new MainThreadJoinAwaiter();
7661
UnityTaskUtil.UnitySynchronizationContext.Post(state=>awaiter.Complete(),null);
7762
return awaiter;
7863
}
7964
}
80-
65+
8166
/// <summary>
8267
/// Awaitable class that will wait for the next frame of the game
8368
/// It starts a task on the main thread that yields and then returns
@@ -93,7 +78,7 @@ private static async Task WaitForNextFrame()
9378
await Task.Yield();
9479
}
9580
}
96-
81+
9782
/// <summary>
9883
/// Interface that implements all the properties needed to make an object awaitable
9984
/// </summary>
@@ -102,7 +87,7 @@ public interface IAwaitable : INotifyCompletion
10287
bool IsCompleted { get; }
10388
void GetResult();
10489
}
105-
90+
10691
/// <summary>
10792
/// Used internally to implement some custom await continuation logic
10893
/// </summary>
@@ -130,5 +115,3 @@ public void GetResult()
130115
}
131116

132117
}
133-
134-

Tests/Runtime/AwaitersTests.cs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,59 @@ namespace Gameframe.Async.Tests
99
{
1010
public class AwaitersTests
1111
{
12-
[UnityTest, Timeout(1000)]
12+
[UnityTest, Timeout(10000)]
1313
public IEnumerator TestBackgroundAndMainThreadAwaiters()
1414
{
1515
yield return null;
1616
var task = DoTest();
1717
yield return task.AsIEnumerator();
1818
}
19-
19+
2020
private static async Task DoTest()
2121
{
2222
Assert.IsTrue(UnityTaskUtil.UnitySynchronizationContext != null);
23-
23+
2424
//Start on unity thread
2525
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread);
2626

2727
//Test Migration Multiple times just to be sure
28+
Debug.Log("-- Loop 10 Times --");
2829
for (int i = 0; i < 10; i++)
2930
{
3031
//Migrate to background thread
31-
await Awaiters.BackgroundThread;
32+
Debug.Log("Await Background");
33+
await Awaiters.BackgroundThread;
3234
Assert.IsFalse(UnityTaskUtil.CurrentThreadIsUnityThread,$"Expected to be on background thread. CurrentThread:{Thread.CurrentThread.ManagedThreadId} UnityThreadId:{UnityTaskUtil.UnityThreadId}");
33-
35+
3436
//Migrate back to main thread
37+
Debug.Log("Await Main");
3538
await Awaiters.MainUnityThread;
3639
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread,$"Expected to be on main thread. CurrentThread:{Thread.CurrentThread.ManagedThreadId} UnityThreadId:{UnityTaskUtil.UnityThreadId}");
3740
}
38-
41+
Debug.Log("-- Loop Complete --");
42+
3943
//Await the main thread when already on the main thread should do nothing
44+
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread,$"Expected to be on main thread. CurrentThread:{Thread.CurrentThread.ManagedThreadId} UnityThreadId:{UnityTaskUtil.UnityThreadId}");
45+
Debug.Log("Await Main");
4046
await Awaiters.MainUnityThread;
4147
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread);
42-
48+
4349
//Await the next frame
4450
int frame = Time.frameCount;
51+
Debug.Log("Await Next Frame");
4552
await Awaiters.NextFrame;
4653
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread);
4754
Assert.IsTrue(Time.frameCount == frame+1);
48-
55+
4956
//Test can await next frame from background thread and then resume on background thread
57+
Debug.Log("Await Background");
5058
await Awaiters.BackgroundThread;
5159
Assert.IsFalse(UnityTaskUtil.CurrentThreadIsUnityThread);
60+
Debug.Log("Await Next Frame");
5261
await Awaiters.NextFrame;
62+
//Confirm we're still on the background thread
5363
Assert.IsFalse(UnityTaskUtil.CurrentThreadIsUnityThread);
5464
}
55-
65+
5666
}
57-
}
67+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "com.gameframe.async",
33
"displayName": "Gameframe.Async",
4-
"version": "1.0.4",
4+
"version": "1.0.5",
55
"description": "> Async task utility package for Unity \n> Helper methods for starting tasks on the Unity thread. \n> Start and await coroutines from any thread.",
66
"keywords": [],
77
"author": {

0 commit comments

Comments
 (0)