Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
<h1 align="center">Gameframe.Async 👋</h1>

<!-- BADGE-START -->
[![Build Status](https://travis-ci.org/coryleach/UnityAsync.svg?branch=master)](https://travis-ci.org/coryleach/UnityAsync)
[![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)
![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/coryleach/UnityAsync?include_prereleases)
[![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/)
[![license](https://img.shields.io/github/license/coryleach/UnityAsync)](https://github.com/coryleach/UnityAsync/blob/master/LICENSE)

[![twitter](https://img.shields.io/twitter/follow/coryleach.svg?style=social)](https://twitter.com/coryleach)
<!-- BADGE-END -->

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

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

Find the manifest.json file in the Packages folder of your project and edit it to look like this:
```js
{
"dependencies": {
"com.gameframe.async": "https://github.com/coryleach/UnityAsync.git#1.0.4",
"com.gameframe.async": "https://github.com/coryleach/UnityAsync.git#1.0.5",
...
},
}
```

<!-- DOC-START -->
<!--
<!--
Changes between 'DOC START' and 'DOC END' will not be modified by readme update scripts
-->

Expand Down Expand Up @@ -95,8 +92,8 @@ await Awaiters.MainUnityThread;


## Show your support

Give a ⭐️ if this project helped you!
{AUTHOR.KOFI}

***
_This README was generated with ❤️ by [Gameframe.Packages](https://github.com/coryleach/unitypackages)_
43 changes: 13 additions & 30 deletions Runtime/Awaiters.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using UnityEngine;

namespace Gameframe.Async
{
Expand All @@ -9,17 +10,17 @@ public static class Awaiters
private static readonly WaitForBackground _waitForBackground = new WaitForBackground();
private static readonly WaitForUnityThread _waitForUnityUnityThread = new WaitForUnityThread();
private static readonly WaitForUpdate _waitForUpdate = new WaitForUpdate();

/// <summary>
/// Await this property to migrate an async method to a background thread
/// </summary>
public static WaitForBackground BackgroundThread => _waitForBackground;

/// <summary>
/// Await this property to migrate to the Unity main thread.
/// </summary>
public static WaitForUnityThread MainUnityThread => _waitForUnityUnityThread;

/// <summary>
/// Await this property to resume on the same context after the game has advanced a frame
/// </summary>
Expand All @@ -32,35 +33,19 @@ private class BackgroundThreadJoinAwaiter : AbstractThreadJoinAwaiter
{
public override void OnCompleted(Action continuation)
{
if (isCompleted)
{
throw new InvalidOperationException("Continuation is invalid. This awaiter is already completed.");
}
_continuation = continuation;
Complete();
Task.Run(continuation);
}
}

public IAwaitable GetAwaiter()
{
//Doing Task.Run(()=>{}).ConfigureAwait(false) will apparently sometimes still resume on the main thread
//Updated to the below pattern to ensure we actually will be running in the background when we resume
var awaiter = new BackgroundThreadJoinAwaiter();
Task.Run(async () =>
{
//Doing complete immediately without a yield appears to cause the awaiter to never resume
//I'm not entirely sure as to why.
//I suspected maybe Complete() was getting called before the the method doing the awaiting could add its continuation
//However when I added a check and exception for this I did not see it get thrown.
//Adding the await Task.Yield however appeared to get Unit tests to consistently pass.
await Task.Yield();
awaiter.Complete();
});
return awaiter;
return new BackgroundThreadJoinAwaiter();;
}
}

public class WaitForUnityThread
{
{
private class MainThreadJoinAwaiter : AbstractThreadJoinAwaiter
{
public override void OnCompleted(Action continuation)
Expand All @@ -69,15 +54,15 @@ public override void OnCompleted(Action continuation)

}
}

public IAwaitable GetAwaiter()
{
var awaiter = new MainThreadJoinAwaiter();
UnityTaskUtil.UnitySynchronizationContext.Post(state=>awaiter.Complete(),null);
return awaiter;
}
}

/// <summary>
/// Awaitable class that will wait for the next frame of the game
/// It starts a task on the main thread that yields and then returns
Expand All @@ -93,7 +78,7 @@ private static async Task WaitForNextFrame()
await Task.Yield();
}
}

/// <summary>
/// Interface that implements all the properties needed to make an object awaitable
/// </summary>
Expand All @@ -102,7 +87,7 @@ public interface IAwaitable : INotifyCompletion
bool IsCompleted { get; }
void GetResult();
}

/// <summary>
/// Used internally to implement some custom await continuation logic
/// </summary>
Expand Down Expand Up @@ -130,5 +115,3 @@ public void GetResult()
}

}


30 changes: 20 additions & 10 deletions Tests/Runtime/AwaitersTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,59 @@ namespace Gameframe.Async.Tests
{
public class AwaitersTests
{
[UnityTest, Timeout(1000)]
[UnityTest, Timeout(10000)]
public IEnumerator TestBackgroundAndMainThreadAwaiters()
{
yield return null;
var task = DoTest();
yield return task.AsIEnumerator();
}

private static async Task DoTest()
{
Assert.IsTrue(UnityTaskUtil.UnitySynchronizationContext != null);

//Start on unity thread
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread);

//Test Migration Multiple times just to be sure
Debug.Log("-- Loop 10 Times --");
for (int i = 0; i < 10; i++)
{
//Migrate to background thread
await Awaiters.BackgroundThread;
Debug.Log("Await Background");
await Awaiters.BackgroundThread;
Assert.IsFalse(UnityTaskUtil.CurrentThreadIsUnityThread,$"Expected to be on background thread. CurrentThread:{Thread.CurrentThread.ManagedThreadId} UnityThreadId:{UnityTaskUtil.UnityThreadId}");

//Migrate back to main thread
Debug.Log("Await Main");
await Awaiters.MainUnityThread;
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread,$"Expected to be on main thread. CurrentThread:{Thread.CurrentThread.ManagedThreadId} UnityThreadId:{UnityTaskUtil.UnityThreadId}");
}

Debug.Log("-- Loop Complete --");

//Await the main thread when already on the main thread should do nothing
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread,$"Expected to be on main thread. CurrentThread:{Thread.CurrentThread.ManagedThreadId} UnityThreadId:{UnityTaskUtil.UnityThreadId}");
Debug.Log("Await Main");
await Awaiters.MainUnityThread;
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread);

//Await the next frame
int frame = Time.frameCount;
Debug.Log("Await Next Frame");
await Awaiters.NextFrame;
Assert.IsTrue(UnityTaskUtil.CurrentThreadIsUnityThread);
Assert.IsTrue(Time.frameCount == frame+1);

//Test can await next frame from background thread and then resume on background thread
Debug.Log("Await Background");
await Awaiters.BackgroundThread;
Assert.IsFalse(UnityTaskUtil.CurrentThreadIsUnityThread);
Debug.Log("Await Next Frame");
await Awaiters.NextFrame;
//Confirm we're still on the background thread
Assert.IsFalse(UnityTaskUtil.CurrentThreadIsUnityThread);
}

}
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "com.gameframe.async",
"displayName": "Gameframe.Async",
"version": "1.0.4",
"version": "1.0.5",
"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.",
"keywords": [],
"author": {
Expand Down