Last active
October 20, 2016 00:04
-
-
Save raizam/df2f62801ab989dbb55226d911dd917f to your computer and use it in GitHub Desktop.
This monogame component helps handling task execution in a background thread, and synchronization in the game thread.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Threading.Tasks; | |
using Microsoft.Xna.Framework; | |
namespace Monogame.Components | |
{ | |
/* | |
public class TaskManagerTest : Game | |
{ | |
GraphicsDeviceManager graphics; | |
TaskManagerComponent taskManager; | |
Color clearColor = Color.CornflowerBlue; | |
private int gameThreadId; | |
public TaskManagerTest() | |
{ | |
graphics = new GraphicsDeviceManager(this); | |
} | |
protected override void Initialize() | |
{ | |
this.gameThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; | |
taskManager = new TaskManagerComponent(this); | |
Components.Add(taskManager); | |
taskManager.ExecuteInBackground(() => | |
{ | |
System.Threading.Thread.Sleep(2000); | |
//ThrowIfNotInGameThread(); //throws here | |
return Color.Aqua; | |
}).Then(r => | |
{ | |
//Here we are back in the game thread, OnUpdate() | |
clearColor = r.Result; | |
ThrowIfNotInGameThread(); | |
}); | |
base.Initialize(); | |
} | |
private void ThrowIfNotInGameThread() | |
{ | |
if (System.Threading.Thread.CurrentThread.ManagedThreadId != gameThreadId) | |
throw new InvalidOperationException("This operation must be executed in the main thread"); | |
} | |
protected override void Draw(GameTime gameTime) | |
{ | |
GraphicsDevice.Clear(clearColor); | |
base.Draw(gameTime); | |
} | |
} | |
*/ | |
/// <summary> | |
/// This component provides a simple background threading mecanism, | |
/// and synchronization operation in the main thread when the task is done | |
/// </summary> | |
public class TaskManagerComponent : GameComponent | |
{ | |
public TaskManagerComponent(Game game) : base(game) { this.UpdateOrder = -1; } | |
readonly System.Collections.Concurrent.ConcurrentQueue<Action> _actionQueue = new System.Collections.Concurrent.ConcurrentQueue<Action>(); | |
public override void Update(GameTime gameTime) | |
{ | |
Action action; | |
while (_actionQueue.TryDequeue(out action)) | |
{ | |
action(); | |
} | |
base.Update(gameTime); | |
} | |
public GameTask<T> ExecuteInBackground<T>(Func<T> background, bool longRunning = false) | |
{ | |
var task = new GameTask<T>(this, Task.Factory.StartNew(background, longRunning ? TaskCreationOptions.LongRunning : TaskCreationOptions.PreferFairness)); | |
return task; | |
} | |
public GameTask ExecuteInBackground(Action background, bool longRunning = false) | |
{ | |
var task = new GameTask(this, Task.Factory.StartNew(background, longRunning ? TaskCreationOptions.LongRunning : TaskCreationOptions.PreferFairness)); | |
return task; | |
} | |
#region Nested | |
public class GameTask | |
{ | |
internal GameTask(TaskManagerComponent manager, Task task) | |
{ | |
this.manager = manager; | |
this.task = task; | |
} | |
readonly protected Task task; | |
readonly protected TaskManagerComponent manager; | |
public void Then(Action<Task> toExecuteInGameThread) | |
{ | |
task.ContinueWith(t => manager._actionQueue.Enqueue(() => toExecuteInGameThread(t)), TaskContinuationOptions.ExecuteSynchronously); | |
} | |
} | |
public class GameTask<T> : GameTask | |
{ | |
internal GameTask(TaskManagerComponent manager, Task<T> task) : base(manager, task){} | |
public void Then(Action<Task<T>> toExecuteInGameThread) | |
{ | |
((Task<T>)task).ContinueWith(t => manager._actionQueue.Enqueue(() => toExecuteInGameThread(t)), TaskContinuationOptions.ExecuteSynchronously); | |
} | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment