网上演练
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.9 KiB

// Needed for Workaround
#if !NET_4_6
using System;
using LinqInternal.Collections.ThreadSafe;
using LinqInternal.Threading.Needles;
namespace LinqInternal.Threading
{
/// <summary>
/// Represents a context to execute operation without reentry.
/// </summary>
[System.Diagnostics.DebuggerNonUserCode]
internal sealed class ReentryGuard
{
private readonly RuntimeUniqueIdProdiver.UniqueId _id;
private readonly SafeQueue<Action> _workQueue;
/// <summary>
/// Initializes a new instance of the <see cref="ReentryGuard" /> class.
/// </summary>
public ReentryGuard()
{
_workQueue = new SafeQueue<Action>();
_id = RuntimeUniqueIdProdiver.GetNextId();
}
/// <summary>
/// Gets a value indicating whether or not the current thread did enter.
/// </summary>
public bool IsTaken
{
get { return ReentryGuardHelper.IsTaken(_id); }
}
/// <summary>
/// Executes an operation-
/// </summary>
/// <param name="operation">The operation to execute.</param>
/// <returns>Returns a promise to finish the execution.</returns>
public IPromise Execute(Action operation)
{
var result = AddExecution(operation, _workQueue);
ExecutePending(_workQueue, _id);
return result;
}
/// <summary>
/// Executes an operation-
/// </summary>
/// <typeparam name="T">The return value of the operation.</typeparam>
/// <param name="operation">The operation to execute.</param>
/// <returns>Returns a promise to finish the execution.</returns>
public IPromise<T> Execute<T>(Func<T> operation)
{
var result = AddExecution(operation, _workQueue);
ExecutePending(_workQueue, _id);
return result;
}
private static IPromise AddExecution(Action action, SafeQueue<Action> queue)
{
var promised = new Promise(false);
var result = new ReadOnlyPromise(promised, false);
queue.Add
(
() =>
{
try
{
action.Invoke();
promised.SetCompleted();
}
catch (Exception exception)
{
promised.SetError(exception);
}
}
);
return result;
}
private static IPromise<T> AddExecution<T>(Func<T> action, SafeQueue<Action> queue)
{
var promised = new PromiseNeedle<T>(false);
var result = new ReadOnlyPromiseNeedle<T>(promised, false);
queue.Add
(
() =>
{
try
{
promised.Value = action.Invoke();
}
catch (Exception exception)
{
promised.SetError(exception);
}
}
);
return result;
}
private static void ExecutePending(SafeQueue<Action> queue, RuntimeUniqueIdProdiver.UniqueId id)
{
var didEnter = false;
try
{
didEnter = ReentryGuardHelper.Enter(id);
if (!didEnter)
{
// called from inside this method - skip
return;
}
Action action;
while (queue.TryTake(out action))
{
action.Invoke();
}
}
finally
{
if (didEnter)
{
ReentryGuardHelper.Leave(id);
}
}
}
}
}
#endif