Skip to content

Instantly share code, notes, and snippets.

@raizam
Last active October 20, 2016 00:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raizam/df2f62801ab989dbb55226d911dd917f to your computer and use it in GitHub Desktop.
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.
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