How to do WaitUntil in async? - c#

All I can find online talking about await in async is teaching me how to "wait for a certain period of time", which is not what I want.
I want it to wait until a certain condition is met.
Just lile
yield return new WaitUntil(()=>conditionIsMet);
in Coroutine.
I want to do something like
await Task.WaitUntil(()=>conditionIsMet);
Is such thing possible?
Could somebody please be so kind and help me out?
Thank you very much for your help.

you can use UniTask Plugin which Provides an efficient allocation free async/await integration for Unity.
it has a lot of features and it is easy to use.
First download it from here,then include it in your project and use it like this :
using Cysharp.Threading.Tasks;
using UnityEngine;
public class Test : MonoBehaviour
{
bool _condition;
// Start is called before the first frame update
void Start()
{
_ = ProcessAsyncTask();
}
public async UniTask ProcessAsyncTask()
{
await UniTask.WaitUntil( ()=> ConditionResult());
}
public bool ConditionResult()
{
// _condition
return _condition;
}
}

Wouldn't this basically simply be something like
public static class TaskUtils
{
public static Task WaitUntil(Func<bool> predicate)
{
while (!predicate()) { }
}
}
though for the love of your CPU I would actually rather give your task certain sleep intervals like
public static class TaskUtils
{
public static async Task WaitUntil(Func<bool> predicate, int sleep = 50)
{
while (!predicate())
{
await Task.Delay(sleep);
}
}
}
and now you could e.g. use something like
public class Example : MonoBehaviour
{
public bool condition;
private void Start()
{
Task.Run(async ()=> await YourTask());
}
public async Task YourTask()
{
await TaskUtils.WaitUntil(IsConditionTrue);
// or as lambda
//await TaskUtils.WaitUntil(() => condition);
Debug.Log("Hello!");
}
private bool IsConditionTrue()
{
return condition;
}
}

you can create your own ConsitionCheker method, and use it in your MainFunction that gets a boolian which awaits for your condition result
public async Task<bool> CheckCondition()
{
While(true){
// check the condition
if(mycondition is true)
break;
}
return true;
}
public void Do(bool consitionResult)
{
if(consitionResult){
// codes
}
}
usage :
public async void Test()
{
// waiting for condition met
// pass the condition result
Do(await CheckCondition());
}

Related

How to declare and await an async delegate?

For some reason, despite this question coming up a lot in my googling, I can't seem to find an actual answer. Maybe I'm just using delegates wrong, I'm not sure. I'm happy for alternative ways of handling this if it's an X-Y problem.
Say I have this:
public class SomeLibrary
{
public delegate void OnSomethingHappened(EventInfo eventInfo);
public OnSomethingHappened onSomethingHappened;
public void SomeMethod()
{
// ...
// Something happened here, so we'd better trigger the event
onSomethingHappened?.Invoke(eventInfo);
// ...
}
}
public class MyCode
{
public void SomeInitialisationMethod()
{
SomeLibrary someLibrary = new SomeLibrary();
someLibrary.onSomethingHappened += SomeEventHandler;
}
private void SomeEventHandler(EventInfo eventInfo)
{
DoSyncProcessing(eventInfo);
}
}
That should all be fine (barring silly typos).
Now imagine my regular synchronous DoSyncProcessing function suddenly has to become asyncronous, like in this magic non-functional code:
public class SomeLibrary
{
public async delegate Task OnSomethingHappened(EventInfo eventInfo); // <<< IDK what I'm doing here!
public OnSomethingHappened onSomethingHappened;
public void SomeMethod()
{
// ...
// Something happened here, so we'd better trigger the event
await onSomethingHappened?.Invoke(eventInfo); // <<< IDK what I'm doing here either!
// ...
}
}
public class MyCode
{
public void SomeInitialisationMethod()
{
SomeLibrary someLibrary = new SomeLibrary();
someLibrary.onSomethingHappened += SomeEventHandler;
}
private async Task SomeEventHandler(EventInfo eventInfo)
{
await DoAsyncProcessing(eventInfo);
}
}
How can I handle that? What's the correct way to do this?
The async modifier affects the method implementation, not the signature. So change this:
public async delegate Task OnSomethingHappened(EventInfo eventInfo);
To this:
public delegate Task OnSomethingHappened(EventInfo eventInfo);
and your code will work.

Non blocking wait for condition evaluation in c#

I have a class which has a property called ActiveDelay which is used to define a duration during which a condition evaluation should wait before checking if the condition is still true after that time. The property SetpointA is the value used to compare the given value to.
Below is what I am currently doing
public void EvaluateCondition(T value)
{
if(value.Equals(SetpointA))
{
Task.Delay(ActiveDelay).ContinueWith(_ => EvaluateConditionDelayed(GetValue())).Wait();
}
}
private void EvaluateConditionDelayed(object value)
{
if (value.Equals(SetpointA))
{
Console.WriteLine("Waited and worked");
}
else
{
Console.WriteLine("Condition now false");
}
}
I am calling the function EvaluateCondition twice, once with a TimeSpan of 5 seconds and another time with a TimeSpan of 2 seconds and I expect that the 2 second call should finish before the 5 second call but what actually happens is that the 5 second call waits and then the 2 second call waits.
I assume there is somethings to do with async and await here but I haven't found information that helps me.
Something I want to make absolutely clear, THESE DELAYS SHOULD NOT PAUSE THE PROGRAM, they should only wait externally and allow the rest of the program to run unaffected.
EXTENSIVE CODE SECTION
Here is an extensive version of the above
public class AlarmCondition
{
#region Property declaration
public TimeSpan ActiveDelay { get; set; } // Need to be historised ?
public TimeSpan ClearDelay { get; set; } // Need to be historised ?
#endregion
#region Constructor
public AlarmCondition() { }
public AlarmCondition(TimeSpan activeDelay, TimeSpan clearDelay)
{
ActiveDelay = activeDelay;
ClearDelay = clearDelay;
}
#endregion
}
public class EqualCondition<T> : AlarmCondition
{
#region Property declaration
public T SetpointA { get; }
#endregion
#region Constructor
public EqualCondition() { }
public EqualCondition(TimeSpan activeDelay, TimeSpan clearDelay) : base(activeDelay, clearDelay)
{
SetpointA = setpointA;
}
#endregion
public void EvaluateCondition(T value)
{
if(value.Equals(SetpointA))
{
Task.Delay(ActiveDelay).ContinueWith(_ => EvaluateConditionDelayed(value));
}
}
private void EvaluateConditionDelayed(T value)
{
if (value.Equals(SetpointA))
{
Console.WriteLine("Waited and worked");
}
else
{
Console.WriteLine("Condition now false");
}
}
}
// In another file and namespace
public class ConsoleDisplay
{
public static void Main(string[] args)
{
EqualCondition<bool> condition1 = new EqualCondition<bool>(new TimeSpan(0, 0, 5), new TimeSpan(0, 0, 5));
EqualCondition<bool> condition2 = new EqualCondition<bool>(new TimeSpan(0, 0, 2), new TimeSpan(0, 0, 5));
condition1.EvaluateCondition(true);
condition2.EvaluateCondition(true);
}
}
You can return Task from your method so the caller will decide if he wants to wait for the result. For example:
public async Task EvaluateCondition(T value)
{
if(value.Equals(SetpointA))
{
await Task.Delay(ActiveDelay);
EvaluateConditionDelayed(GetValue());
}
}
Or just remove .Wait() (which blocks) from your current implementation if you don't want caller to have an option for such decision. The task should still print in the console even without it (if your program runs long enough):
public void EvaluateCondition(T value)
{
if(value.Equals(SetpointA))
{
Task.Delay(ActiveDelay).ContinueWith(_ => EvaluateConditionDelayed(GetValue()));
}
}
UPD
To start multiple EvaluateCondition and wait for them to finish in parallel you can use Task.WhenAll:
var ev1Task = EvaluateCondition(someVal1);
var ev2Task = EvaluateCondition(someVal2);
await Task.WhenAll(ev1Task, ev2Task);
If you don't want to await then just skip the await Task.WhenAll(ev1Task, ev2Task) (and fix the warnings).

API methods must wait until critical method is done

I have MVC API controller.
One method in this controller is critical.
This mean that all other API methods must wait util this method is done.
My basic idea is to block threads in constructor.
But I am not sure if this is so smart?
public class TestApi : Controller
{
private static bool wait = false;
public TestApi()
{
// wait if critical method is working.
while (wait)
{
System.Threading.Thread.Sleep(100);
}
}
[HttpPost]
public void PostCriticalMethod()
{
try
{
wait = true;
// do critical work
}
finally
{
wait = false;
}
}
// Many non critical API methods...
}
Solution two:
public class TestApi : Controller
{
private static bool wait = false;
private static AutoResetEvent waitHandle = new AutoResetEvent(false);
public TestApi()
{
// wait if critical method is working.
if (wait) waitHandle.WaitOne();
}
[HttpPost]
public void PostCriticalMethod()
{
try
{
wait = true;
// do critical work
}
finally {
waitHandle.Set();
wait = false;
}
}
// Many non critical API methods...
}
My solution (This is async version, but non async is even simpler):
In base class (common for all controllers) I add method BlockOtherRequestsBeforeExecute
private static readonly SemaphoreSlim semaphoreInit = new SemaphoreSlim(1, 1);
protected async Task BlockOtherRequestsBeforeExecute(Func<Task> criticalAction)
{
await semaphoreInit.WaitAsync();
try
{
await criticalAction();
}
finally
{
semaphoreInit.Release();
}
}
Then I can call method in secure way if I need to:
await BlockOtherRequestsBeforeExecute(async () => await RestoreDatabase());
Important part is that semaphoreInit must be used in all critical places.
This can be done in constructor of base class, and then all API-s are blocked until critical action is not finished.

"...because this call is not awaited"

using System;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace Rohan.Gateway
{
public class Player
{
private PlayerSocket _mapSocket;
private PlayerSocket _clientSocket;
public int _characterId = -1;
public int _characterType = -1;
public string _characterName = "";
public int _playerId = -1;
public string _dumpFolder = "";
public int _packetIndex;
public PlayerSocket mapSocket
{
get { return this._mapSocket; }
}
public PlayerSocket clientSocket
{
get { return this._clientSocket; }
}
public bool isConnected
{
get { return this._mapSocket.isConnected && this._clientSocket.isConnected; }
}
public Player(Socket clientSocket)
{
this._clientSocket = new PlayerSocket(clientSocket, this, PlayerSocketType.Client);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
socket.Connect(TCPListenerEx.remoteAddress, 22100);
this._mapSocket = new PlayerSocket(socket, this, PlayerSocketType.MapServer);
this.ValidateConnection();
}
public bool ValidateConnection()
{
if (!this.isConnected)
{
this.Disconnect();
return false;
}
return true;
}
public void Disconnect()
{
this._mapSocket.Disconnect();
this._clientSocket.Disconnect();
}
public void ReceiveClientData()
{
if (this.ValidateConnection())
{
this._clientSocket.ReceiveAsync();
}
}
public void DispatchClientData()
{
if (this.ValidateConnection())
{
this._mapSocket.SendAsync(this._clientSocket.reader);
}
}
public void ReceiveMapserverData()
{
if (this.ValidateConnection())
{
this._mapSocket.ReceiveAsync();
}
}
public void DispatchMapserverData()
{
if (this.ValidateConnection())
{
this._clientSocket.SendAsync(this._mapSocket.reader);
}
}
}
}
On the lines below, I get this warning
because this call is not awaited
public void ReceiveClientData()
{
if (this.ValidateConnection())
{
this._clientSocket.ReceiveAsync();
}
}
public void DispatchClientData()
{
if (this.ValidateConnection())
{
this._mapSocket.SendAsync(this._clientSocket.reader);
}
}
public void ReceiveMapserverData()
{
if (this.ValidateConnection())
{
this._mapSocket.ReceiveAsync();
}
}
public void DispatchMapserverData()
{
if (this.ValidateConnection())
{
this._clientSocket.SendAsync(this._mapSocket.reader);
}
}
Why am I getting this error?
In response to the comment asking:
Have you tried adding async to the signature then use await for the call of the method
You answered:
Yes, i did it already
But none of the code you posted shows this. And this is in fact the right way to correct this warning message.
Without a good Minimal, Complete, and Verifiable example that shows clearly all of the relevant types (including the PlayerSocket type and how these methods are being called) it's impossible to say for sure how you should fix your code. Your options include:
Disable the warning with the #pragma warning directive
Implicitly suppress the warning by assigning the returned Task object from each ...Async() method to a local variable. E.g.:
public void ReceiveClientData()
{
if (this.ValidateConnection())
{
var _ = this._clientSocket.ReceiveAsync();
}
}
Call the asynchronous operation synchronously. E.g.:
public void ReceiveClientData()
{
if (this.ValidateConnection())
{
this._clientSocket.ReceiveAsync().Wait();
}
}
Correctly await the asynchronous operation. This is, frankly, by far the best choice but will be the most complicated. Primary advantage is that you get the benefit of asynchronous operation (i.e. the code doesn't block waiting for the operation to complete), but you will still be able to observe any exception that might occur. Primary disadvantage is that you will have to change each method from void to async Task, and then effect the same change to each method's caller. And each caller of those callers, and so on, until you get to the top of the call stack for the thread.
Personally, I would strongly recommend the third or (especially) the fourth option. They are the only options that allow you to add try/catch to observe exceptions. There are some scenarios where the first and second options might make sense, but I would not say that doing socket I/O would be one of those scenarios.
There are a number of existing Stack Overflow questions and answers that go into more detail as to how to deal with this sort of thing. Please decide which approach you want to use, do some research, and if you have a specific issue, post a question that includes a good code example, so that an appropriate answer can be provided.

Win8 C# trouble with async/await

Why in the second case the exception is thrown?
async void f() {
await media.InitializeAsync();
isInit = true;
capturePreview.Source = media;
await media.StartPreviewAsync(); // Ok
}
// ------------------------------------------
void f() {
StaticClass.g(capturePreview.Source);
}
public static class StaticClass {
public static async void g(MediaSource source) {
await media.InitializeAsync();
isInit = true;
source = media;
await media.StartPreviewAsync(); // Unknown Exception (It's seems that media isn't init)
}
}
The f() function use a function which include async.
So I think the f() should be signed async as well.
Like this: void async f(){...}
If you really want media to be initialized, why don't you do the rest of the code in the .done function ?
void f() {
StaticClass.g(capturePreview.Source);
}
public static class StaticClass {
public static async void g(MediaSource source) {
media.InitializeAsync().done(
isInit = true;
source = media;
await media.StartPreviewAsync(););
}
}
Even if I'm not fully sure you can do an async within a done callback.

Categories

Resources