-
-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use a ComThread for all Com Actions
- Loading branch information
Antoine Aflalo
committed
Feb 26, 2019
1 parent
4c7fc4f
commit 4fbc88c
Showing
22 changed files
with
230 additions
and
124 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
98 changes: 98 additions & 0 deletions
98
SoundSwitch.Audio.Manager/Interop/Threading/ComTaskScheduler.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace SoundSwitch.Audio.Manager.Interop.Threading | ||
{ | ||
internal sealed class ComTaskScheduler : TaskScheduler, IDisposable | ||
{ | ||
/// <summary>The STA threads used by the scheduler.</summary> | ||
private readonly Thread _thread; | ||
|
||
/// <summary>Stores the queued tasks to be executed by our pool of STA threads.</summary> | ||
private BlockingCollection<Task> _tasks; | ||
|
||
/// <summary>Initializes a new instance of the StaTaskScheduler class with the specified concurrency level.</summary> | ||
public ComTaskScheduler() | ||
{ | ||
// Initialize the tasks collection | ||
_tasks = new BlockingCollection<Task>(); | ||
|
||
_thread = new Thread(() => | ||
{ | ||
// Continually get the next task and try to execute it. | ||
// This will continue until the scheduler is disposed and no more tasks remain. | ||
foreach (var t in _tasks.GetConsumingEnumerable()) | ||
{ | ||
TryExecuteTask(t); | ||
} | ||
|
||
//lightweight pump of the thread | ||
Thread.CurrentThread.Join(1); | ||
}); | ||
|
||
_thread.IsBackground = true; | ||
_thread.SetApartmentState(ApartmentState.STA); | ||
|
||
// Start all of the threads | ||
_thread.Start(); | ||
} | ||
|
||
public int ThreadId | ||
{ | ||
get { return _thread == null ? -1 : _thread.ManagedThreadId; } | ||
} | ||
|
||
/// <summary>Gets the maximum concurrency level supported by this scheduler.</summary> | ||
public override int MaximumConcurrencyLevel | ||
{ | ||
get { return 1; } | ||
} | ||
|
||
/// <summary> | ||
/// Cleans up the scheduler by indicating that no more tasks will be queued. | ||
/// This method blocks until all threads successfully shutdown. | ||
/// </summary> | ||
public void Dispose() | ||
{ | ||
if (_tasks == null) return; | ||
|
||
// Indicate that no new tasks will be coming in | ||
_tasks.CompleteAdding(); | ||
|
||
_thread.Join(); | ||
|
||
// Cleanup | ||
_tasks.Dispose(); | ||
_tasks = null; | ||
} | ||
|
||
/// <summary>Queues a Task to be executed by this scheduler.</summary> | ||
/// <param name="task">The task to be executed.</param> | ||
protected override void QueueTask(Task task) | ||
{ | ||
// Push it into the blocking collection of tasks | ||
_tasks.Add(task); | ||
} | ||
|
||
/// <summary>Provides a list of the scheduled tasks for the debugger to consume.</summary> | ||
/// <returns>An enumerable of all tasks currently scheduled.</returns> | ||
protected override IEnumerable<Task> GetScheduledTasks() | ||
{ | ||
// Serialize the contents of the blocking collection of tasks for the debugger | ||
return _tasks.ToArray(); | ||
} | ||
|
||
/// <summary>Determines whether a Task may be inlined.</summary> | ||
/// <param name="task">The task to be executed.</param> | ||
/// <param name="taskWasPreviouslyQueued">Whether the task was previously queued.</param> | ||
/// <returns>true if the task was successfully inlined; otherwise, false.</returns> | ||
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) | ||
{ | ||
//Never run inline, it HAS to be run on the COM thread | ||
return false; | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace SoundSwitch.Audio.Manager.Interop.Threading | ||
{ | ||
internal static class ComThread | ||
{ | ||
private static readonly ComTaskScheduler COM_SCHEDULER = new ComTaskScheduler(); | ||
|
||
private static bool InvokeRequired | ||
{ | ||
get { return Thread.CurrentThread.ManagedThreadId != Scheduler.ThreadId; } | ||
} | ||
|
||
private static ComTaskScheduler Scheduler | ||
{ | ||
get { return COM_SCHEDULER; } | ||
} | ||
|
||
/// <summary> | ||
/// Asserts that the execution following this statement is running on the ComThreads | ||
/// <exception cref="InvalidThreadException">Thrown if the assertion fails</exception> | ||
/// </summary> | ||
public static void Assert() | ||
{ | ||
if (InvokeRequired) | ||
throw new InvalidThreadException(String.Format("This operation must be run on the ComThread ThreadId: {0}", Scheduler.ThreadId)); | ||
} | ||
|
||
public static void Invoke(Action action) | ||
{ | ||
if (!InvokeRequired) | ||
{ | ||
action(); | ||
return; | ||
} | ||
|
||
BeginInvoke(action).Wait(); | ||
} | ||
|
||
public static Task BeginInvoke(Action action) | ||
{ | ||
return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, COM_SCHEDULER); | ||
} | ||
|
||
public static T Invoke<T>(Func<T> func) | ||
{ | ||
if (!InvokeRequired) | ||
return func(); | ||
|
||
return BeginInvoke(func).Result; | ||
} | ||
|
||
public static Task<T> BeginInvoke<T>(Func<T> func) | ||
{ | ||
return Task<T>.Factory.StartNew(func, CancellationToken.None, TaskCreationOptions.None, COM_SCHEDULER); | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
SoundSwitch.Audio.Manager/Interop/Threading/InvalidThreadException.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
|
||
namespace SoundSwitch.Audio.Manager.Interop.Threading | ||
{ | ||
public sealed class InvalidThreadException : Exception | ||
{ | ||
|
||
public InvalidThreadException() | ||
{ | ||
|
||
} | ||
|
||
public InvalidThreadException(string message) | ||
: base(message) | ||
{ | ||
} | ||
} | ||
} |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Oops, something went wrong.