110 lines
3.5 KiB
C#
110 lines
3.5 KiB
C#
using System;
|
|||
|
|
using System.Threading;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
|
||
|
|
namespace PCL.Core.Utils.Threading;
|
||
|
|
|
||
|
|
// Partly generated by gpt-5-mini (20250808)
|
||
|
|
public sealed class AsyncManualResetEvent : IDisposable
|
||
|
|
{
|
||
|
|
private readonly object _syncLock = new();
|
||
|
|
private TaskCompletionSource<bool> _tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||
|
|
private readonly ManualResetEventSlim _mre = new(false);
|
||
|
|
private bool _disposed;
|
||
|
|
|
||
|
|
public AsyncManualResetEvent(bool initialState = false)
|
||
|
|
{
|
||
|
|
if (!initialState) return;
|
||
|
|
_tcs.SetResult(true);
|
||
|
|
_mre.Set();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 事件是否已触发。
|
||
|
|
/// </summary>
|
||
|
|
public bool IsSet
|
||
|
|
{
|
||
|
|
get { lock (_syncLock) { return _tcs.Task.IsCompleted; } }
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 异步等待。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="cancellationToken">用于结束等待的取消信号</param>
|
||
|
|
public Task WaitAsync(CancellationToken cancellationToken = default)
|
||
|
|
{
|
||
|
|
TaskCompletionSource<bool> t;
|
||
|
|
lock (_syncLock) { t = _tcs; }
|
||
|
|
if (!cancellationToken.CanBeCanceled || t.Task.IsCompleted) return t.Task;
|
||
|
|
return _WaitWithCancellationAsync(t.Task, cancellationToken);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static async Task _WaitWithCancellationAsync(Task waitTask, CancellationToken ct)
|
||
|
|
{
|
||
|
|
var cancelTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||
|
|
using (ct.Register(s => ((TaskCompletionSource<bool>)s!).TrySetResult(true), cancelTcs))
|
||
|
|
{
|
||
|
|
var completed = await Task.WhenAny(waitTask, cancelTcs.Task).ConfigureAwait(false);
|
||
|
|
if (completed == cancelTcs.Task) ct.ThrowIfCancellationRequested();
|
||
|
|
await waitTask.ConfigureAwait(false); // propagate exceptions if any
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 同步等待。
|
||
|
|
/// </summary>
|
||
|
|
public void Wait() => _mre.Wait();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 同步等待,并在超时后结束。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="millisecondsTimeout">等待超时的毫秒数</param>
|
||
|
|
/// <returns>若已触发事件则为 <c>true</c>,否则为 <c>false</c></returns>
|
||
|
|
public bool Wait(int millisecondsTimeout) => _mre.Wait(millisecondsTimeout);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 同步等待,并在超时后结束。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="timeout">等待超时</param>
|
||
|
|
/// <returns>若已触发事件则为 <c>true</c>,否则为 <c>false</c></returns>
|
||
|
|
public bool Wait(TimeSpan timeout) => _mre.Wait(timeout);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 同步等待,并传递用于结束等待的取消信号。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="cancellationToken">用于结束等待的取消信号</param>
|
||
|
|
public void Wait(CancellationToken cancellationToken) => _mre.Wait(cancellationToken);
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 触发事件。
|
||
|
|
/// </summary>
|
||
|
|
public void Set()
|
||
|
|
{
|
||
|
|
lock (_syncLock)
|
||
|
|
{
|
||
|
|
_tcs.TrySetResult(true); // Use TrySetResult to avoid exceptions on repeated Set
|
||
|
|
_mre.Set();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 重置事件。
|
||
|
|
/// </summary>
|
||
|
|
public void Reset()
|
||
|
|
{
|
||
|
|
lock (_syncLock)
|
||
|
|
{
|
||
|
|
if (!_tcs.Task.IsCompleted) return; // already reset
|
||
|
|
_tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||
|
|
_mre.Reset();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Dispose()
|
||
|
|
{
|
||
|
|
if (_disposed) return;
|
||
|
|
_mre.Dispose();
|
||
|
|
_disposed = true;
|
||
|
|
}
|
||
|
|
}
|