Files
UnrealEngine/Engine/Source/Programs/Shared/EpicGames.Core/AsyncEvent.cs
2025-05-18 13:04:45 +08:00

86 lines
2.1 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System.Threading;
using System.Threading.Tasks;
namespace EpicGames.Core
{
/// <summary>
/// Wrapper to allow awaiting an event being signalled, similar to an AutoResetEvent.
/// </summary>
public class AsyncEvent
{
/// <summary>
/// Completion source to wait on
/// </summary>
TaskCompletionSource<bool> _source = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
/// <summary>
/// Legacy name for <see cref="Pulse"/>.
/// </summary>
public void Set() => Pulse();
/// <summary>
/// Pulse the event, allowing any captured copies of the task to continue.
/// </summary>
public void Pulse()
{
for (; ; )
{
TaskCompletionSource<bool> prevSource = _source;
if (prevSource.Task.IsCompleted)
{
// The task source is latched or has been set from another thread. Either way behaves identically wrt the contract of this method.
break;
}
if (Interlocked.CompareExchange(ref _source, new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously), prevSource) == prevSource)
{
prevSource.TrySetResult(true);
break;
}
}
}
/// <summary>
/// Resets an event which is latched to the set state.
/// </summary>
public void Reset()
{
for (; ; )
{
TaskCompletionSource<bool> prevSource = _source;
if (!prevSource.Task.IsCompleted)
{
break;
}
else if (Interlocked.CompareExchange(ref _source, new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously), prevSource) == prevSource)
{
break;
}
}
}
/// <summary>
/// Move the task to completed without returning it to an unset state. A call to Reset() is required to clear it.
/// </summary>
public void Latch()
{
_source.TrySetResult(true);
}
/// <summary>
/// Determines if this event is set
/// </summary>
/// <returns>True if the event is set</returns>
public bool IsSet()
{
return _source.Task.IsCompleted;
}
/// <summary>
/// Waits for this event to be set
/// </summary>
public Task Task => _source.Task;
}
}