The event stops halfway - c#

I am executing an asynchronous anonymous method that is called by an event, but it terminates halfway through without executing half the code.
Method, that called when an event called.
private void OnBlockGenerationTime()
{
Task.Run(async () =>
{
await Task.Delay(10);
if (!ChainMutex.WaitOne(3000))
throw new TimeoutException("Cannot access to blockchain, mutex was held too long.");
var winnerTrx = PoS.GetWinner(Blockchain.LatestBlock.ID);
ChainMutex.ReleaseMutex();
if (winnerTrx == null)
return;
var winner = PoolsSet.TransactionPool.GetTxOut(winnerTrx.Trx.Inputs[0]).Address;
if (winner == CurrentAccount.GetAddress())
{
var (block, reward) = Blockchain.CreateBlock(CurrentAccount.GetPrivateKey()); //here task terminating.
CommonLog.Log(LogElementType.OK, $"Our stake won. A new block with ID {block.ID} was created. {reward} AWT were collected.");
P2P.BroadcastLatestBlock();
}
});
}
Method with infinte task, that calles event:
private void RunNewBlockListening()
{
Task.Run(async () =>
{
while (true)
{
while (GetRemainingToNewBlock() != 0) { await Task.Delay(100); }
OnNewBlockGeneration?.Invoke();
await Task.Delay(1000);
}
});
}
I know that asynchronous methods are executed in different ways, but the marked code is never executed when debagged.

Thank you all for your help, those who are looking for an answer to catching exceptions in anonymous functions, just click on the "Common Language Runtime Exceptions" checkbox in the "Exception parameters" tab (Debugging -> Windows -> Exception Parameters).
That's all.

Related

How to catch exceptions from Task.Run() if not awaited? [duplicate]

This question already has an answer here:
Exception handling in fire and forget for C# 5 (in .net 4.5)
(1 answer)
Closed 2 years ago.
Let's assume I have a console application with Main method, something like this:
public static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) =>
{
Console.WriteLine("App Unobserved");
};
TaskScheduler.UnobservedTaskException += (sender, eventArgs) =>
{
Console.WriteLine("Task Unobserved");
};
Task.Run(async () => await MyAwesomeMethod());
// other awesome code...
Console.ReadLine();
}
public static async Task MyAwesomeMethod()
{
// some useful work
if (something_went_wrong)
throw new Exception();
// other some useful work
}
So, I just run MyAwesomeMethod (fire-and-forget), and want to do some other job, but I also want to know if there any unhandled exceptions. But application finishes successfully without any sign of problem (exception is just swallowed).
How can I handle exception from MyAwesomeMethod(), without awaiting it or using Task.Run(...).Wait()?
So, I just run MyAwesomeMethod (fire-and-forget)... but I also want to know if there any unhandled exceptions. But application finishes successfully without any sign of problem (exception is just swallowed).
That's not "fire and forget", then. "Fire and forget" literally means that you don't care when (or whether) the task completes (or errors).
How can I handle exception from MyAwesomeMethod(), without awaiting it or using Task.Run(...).Wait()?
Use await anyway:
Task.Run(async () => {
try {
await MyAwesomeMethod();
} catch (Exception ex) {
Console.WriteLine(ex);
}
});
You can check the status of your task once it's done.
Task.Run(() => MyAwesomeMethod()).ContinueWith((task) =>
{
if (task.Status == TaskStatus.RanToCompletion && task.Result != null)
{
}
else
{
try
{
Logger.LogError(task.Exception.ToString());
Logger.LogMessage("something_went_wrong");
}
catch { }
}
});
You could for example wrap the code in the background task in a try...catch block and raise an event as soon as you enter the catch block (if you do).
Like
event EventHandler<Exception> exceptionInWorker;
and in the task do
try
{
//do something
}
catch (Exception e)
{
exceptionInWorker?.Invoke(this, e);
}
You can subscribe to TaskScheduler.UnobservedTaskException event as you do but with a handler that takes UnobservedTaskExceptionEventArgs as its second parameter, through it you could access the unhandled exception via its Exception property and log all info about it.

C# event exception not caught in parent method

I`m working on implementing a get method for cache. This method will return to caller if a maximum wait time has passed(in my case 100ms for tests).
My issue is that the exception NEVER reaches the catch, after the timer triggered the event.
Please help me understand why? (I read that events are executed on the same thread, so that should`t be the issue)
public static T Get<T>(string key, int? maxMilisecondsForResponse = null)
{
var result = default(T);
try
{
// Return default if time expired
if (maxMilisecondsForResponse.HasValue)
{
var timer = new System.Timers.Timer(maxMilisecondsForResponse.Value);
timer.Elapsed += OnTimerElapsed;
timer.AutoReset = false;
timer.Enabled = true; // start the timer
}
var externalCache = new CacheServiceClient(BindingName);
Thread.Sleep(3000); // just for testing
}
catch (Exception ex)
{
// why is the exception not caught here?
}
return result;
}
private static void OnTimerElapsed(object source, System.Timers.ElapsedEventArgs e)
{
throw new Exception("Timer elapsed");
}
The timer fires on it's own thread. You can read more about it in this answer.
The answer to your question is to use async methods that can be cancelled. Then you can use a cancellation token source and do it the proper way instead of homebrewing a solution with timers.
You can find a good overview here.
For example:
cts = new CancellationTokenSource();
cts.CancelAfter(2500);
await Task.Delay(10000, cts.Token);
This would cancel the waiting task after 2500 (of 10000) because it took too long. Obviously you need to insert your own logic in a task instead of just waiting.
From MSDN
The Timer component catches and suppresses all exceptions thrown by
event handlers for the Elapsed event. This behavior is subject to
change in future releases of the .NET Framework.
And continues
Note, however, that this is not true of event handlers that execute
asynchronously and include the await operator (in C#) or the Await
operator (in Visual Basic). Exceptions thrown in these event handlers
are propagated back to the calling thread.
Please take a look Exception Handling (Task Parallel Library)
An applied example below:
public class Program
{
static void Main()
{
Console.WriteLine("Begin");
Get<string>("key", 1000);
Console.WriteLine("End");
}
public static T Get<T>(string key, int? maxMilisecondsForResponse = null)
{
var result = default(T);
try
{
var task = Task.Run(async () =>
{
await Task.Delay(maxMilisecondsForResponse.Value);
throw new Exception("Timer elapsed");
});
task.Wait();
}
catch (Exception ex)
{
// why the exception is not catched here?
Console.WriteLine(ex);
}
return result;
}
}
The timer is being executed in the own thread but you can't catch the exception at the caller level. So, it is not a good approach to use timer in this case and you can change it by creating the Task operation.
var result = default(T);
CacheServiceClient externalCache;
if (!Task.Run(() =>
{
externalCache = new CacheServiceClient(BindingName);
return externalCache;
}).Wait(100))//Wait for the 100 ms to complete operation.
{
throw new Exception("Task is not completed !");
}
// Do something
return result;

Understanding async/await vs Wait in C# with "ContinueWith" behavior

One method is a standard async method, like this one :
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
I have tested two implementations, one that use await and the other uses .Wait()
The two implementations are not equal at all because the same tests are failing with the await version but not the Wait() one.
The goal of this method is to "execute a Task returned by the input function, and retry by executing the same function until it works" (with limitations to stop automatically if a certain number of tries is reached).
This works:
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(t =>
{
// Wait for the recursive call to complete
AutoRetryHandlerAsync_Worker(taskToRun).Wait();
});
// Stop
return;
}
}
And this (with async t => and the usage of await instead of t => and the usage of .Wait() doesn't work at all because the result of the recursive call is not awaited before the final return; is executed :
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(async t =>
{
// Wait for the recursive call to complete
await AutoRetryHandlerAsync_Worker(taskToRun);
});
// Stop
return;
}
}
I'm trying to understand why this simple change does change everything, when it's supposed to do the exact same thing : waiting the ContinueWith completion.
If I extract the task ran by the ContinueWith method, I do see the state of the ContinueWith function passing to "ranToCompletion" before the return of the inner await completes.
Why? Isn't it supposed to be awaited?
Concrete testable behaviour
public static void Main(string[] args)
{
long o = 0;
Task.Run(async () =>
{
// #1 await
await Task.Delay(1000).ContinueWith(async t =>
{
// #2 await
await Task.Delay(1000).ContinueWith(t2 => {
o = 10;
});
});
var hello = o;
});
Task.Delay(10000).Wait();
}
Why does var hello = o; is reached before o=10?
Isn't the #1 await supposed to hang on before the execution can continue?
The lambda syntax obscures the fact that you ContinueWith(async void ...).
async void methods are not awaited and any errors they throw will go unobserved.
And to your base question, retrying from within a catch is not a recommended practice anyway. Too much going on, catch blocks should be simple. And bluntly retrying for all exception types is also very suspect. You ought to have an idea what errors could warrant a retry, and let the rest pass.
Go for simplicity and readability:
while (count++ < N)
{
try
{
MainAction();
break;
}
catch(MoreSpecificException ex) { /* Log or Ignore */ }
Delay();
}

Do multiple awaits to the same Task from a single thread resume in FIFO order?

Supposing a Task is created and awaited multiple times from a single thread. Is the resume order FIFO?
Simplistic example: Is the Debug.Assert() really an invariant?
Task _longRunningTask;
async void ButtonStartSomething_Click()
{
// Wait for any previous runs to complete before starting the next
if (_longRunningTask != null) await _longRunningTask;
// Check our invariant
Debug.Assert(_longRunningTask == null, "This assumes awaits resume in FIFO order");
// Initialize
_longRunningTask = Task.Delay(10000);
// Yield and wait for completion
await _longRunningTask;
// Clean up
_longRunningTask = null;
}
Initialize and Clean up are kept to a bare minimum for the sake of simplicity, but the general idea is that the previous Clean up MUST be complete before the next Initialize runs.
The short answer is: no, it's not guaranteed.
Furthermore, you should not use ContinueWith; among other problems, it has a confusing default scheduler (more details on my blog). You should use await instead:
private async void ButtonStartSomething_Click()
{
// Wait for any previous runs to complete before starting the next
if (_longRunningTask != null) await _longRunningTask;
_longRunningTask = LongRunningTaskAsync();
await _longRunningTask;
}
private async Task LongRunningTaskAsync()
{
// Initialize
await Task.Delay(10000);
// Clean up
_longRunningTask = null;
}
Note that this could still have "interesting" semantics if the button can be clicked many times while the tasks are still running.
The standard way to prevent the multiple-execution problem for UI applications is to disable the button:
private async void ButtonStartSomething_Click()
{
ButtonStartSomething.Enabled = false;
await LongRunningTaskAsync();
ButtonStartSomething.Enabled = true;
}
private async Task LongRunningTaskAsync()
{
// Initialize
await Task.Delay(10000);
// Clean up
}
This forces your users into a one-operation-at-a-time queue.
The order of execution is pre-defined, however there is potential race condition on _longRunningTask variable if ButtonStartSomething_Click() is called concurrently from more than one thread (not likely the case).
Alternatively, you can explicitly schedule tasks using a queue. As a bonus a work can be scheduled from non-async methods, too:
void ButtonStartSomething_Click()
{
_scheduler.Add(async() =>
{
// Do something
await Task.Delay(10000);
// Do something else
});
}
Scheduler _scheduler;
class Scheduler
{
public Scheduler()
{
_queue = new ConcurrentQueue<Func<Task>>();
_state = STATE_IDLE;
}
public void Add(Func<Task> func)
{
_queue.Enqueue(func);
ScheduleIfNeeded();
}
public Task Completion
{
get
{
var t = _messageLoopTask;
if (t != null)
{
return t;
}
else
{
return Task.FromResult<bool>(true);
}
}
}
void ScheduleIfNeeded()
{
if (_queue.IsEmpty)
{
return;
}
if (Interlocked.CompareExchange(ref _state, STATE_RUNNING, STATE_IDLE) == STATE_IDLE)
{
_messageLoopTask = Task.Run(new Func<Task>(RunMessageLoop));
}
}
async Task RunMessageLoop()
{
Func<Task> item;
while (_queue.TryDequeue(out item))
{
await item();
}
var oldState = Interlocked.Exchange(ref _state, STATE_IDLE);
System.Diagnostics.Debug.Assert(oldState == STATE_RUNNING);
if (!_queue.IsEmpty)
{
ScheduleIfNeeded();
}
}
volatile Task _messageLoopTask;
ConcurrentQueue<Func<Task>> _queue;
static int _state;
const int STATE_IDLE = 0;
const int STATE_RUNNING = 1;
}
Found the answer under Task.ContinueWith(). It appear to be: no
Presuming await is just Task.ContinueWith() under the hood, there's documentation for TaskContinuationOptions.PreferFairness that reads:
A hint to a TaskScheduler to schedule task in the order in which they were scheduled, so that tasks scheduled sooner are more likely to run sooner, and tasks scheduled later are more likely to run later.
(bold-facing added)
This suggests there's no guarantee of any sorts, inherent or otherwise.
Correct ways to do this
For the sake of someone like me (OP), here's a look at the more correct ways to do this.
Based on Stephen Cleary's answer:
private async void ButtonStartSomething_Click()
{
// Wait for any previous runs to complete before starting the next
if (_longRunningTask != null) await _longRunningTask;
// Initialize
_longRunningTask = ((Func<Task>)(async () =>
{
await Task.Delay(10);
// Clean up
_longRunningTask = null;
}))();
// Yield and wait for completion
await _longRunningTask;
}
Suggested by Raymond Chen's comment:
private async void ButtonStartSomething_Click()
{
// Wait for any previous runs to complete before starting the next
if (_longRunningTask != null) await _longRunningTask;
// Initialize
_longRunningTask = Task.Delay(10000)
.ContinueWith(task =>
{
// Clean up
_longRunningTask = null;
}, TaskContinuationOptions.OnlyOnRanToCompletion);
// Yield and wait for completion
await _longRunningTask;
}
Suggested by Kirill Shlenskiy's comment:
readonly SemaphoreSlim _taskSemaphore = new SemaphoreSlim(1);
async void ButtonStartSomething_Click()
{
// Wait for any previous runs to complete before starting the next
await _taskSemaphore.WaitAsync();
try
{
// Do some initialization here
// Yield and wait for completion
await Task.Delay(10000);
// Do any clean up here
}
finally
{
_taskSemaphore.Release();
}
}
(Please -1 or comment if I've messed something up in either.)
Handling exceptions
Using continuations made me realize one thing: awaiting at multiple places gets complicated really quickly if _longRunningTask can throw exceptions.
If I'm going to use continuations, it looks like I need to top it off by handling all exceptions within the continuation as well.
i.e.
_longRunningTask = Task.Delay(10000)
.ContinueWith(task =>
{
// Clean up
_longRunningTask = null;
}, TaskContinuationOptions.OnlyOnRanToCompletion);
.ContinueWith(task =>
{
// Consume or handle exceptions here
}, TaskContinuationOptions.OnlyOnFaulted);
// Yield and wait for completion
await _longRunningTask;
If I use a SemaphoreSlim, I can do the same thing in the try-catch, and have the added option of bubbling exceptions directly out of ButtonStartSomething_Click.

Using Dispatcher correctly in event to update UI

I'm using dispatchers to update a bound collection from an event. I just ran into a nasty issue where I had two different dispatchers in the same event and it wasn't working. Using the debugger it was completely skipping over the code in the first dispatcher. Putting the entire event in a single dispatcher fixed it. I assume it's because of how the compiler handles it, can anyone confirm this - only one dispatcher per event, at least when dealing with the same elements?
Here is the code, when it gets to the await after (line == 0), it exits the function completely. Later, when line !=0 it runs the "Old style menu" fine. If I put all of the code in a single dispatcher, everything works fine.
private async void ProcessNLS(string parameters) // NET/USB List Info
{
if (parameters.Substring(0, 1) == "A" || (parameters.Substring(0, 1) == "U")) // ASCII x08/2010 Only
{
int line = Convert.ToInt32(parameters.Substring(1, 1));
string text = parameters.Substring(3);
// New Menu, Clear Old - Use Last Received/Holding Menu: See NLT bug
if (line == 0)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
State.Menu.ServiceType = State.holdingMenu.ServiceType;
...
State.Menu.Items.Clear();
});
OnMenuTitleInfoChanged(new MenuTitleInfoChangedArgs(State.Menu));
// Replace Network Top with custom menu
if (State.Menu.LayerInfo == LayerTypes.NetworkTop)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
State.Menu.Items.Clear();
});
...
}
// Get 1st Advanced Menu
if (Device.SupportsAdvancedMenus & State.Menu.LayerInfo != LayerTypes.NetworkTop)
{
...
}
}
// Old style menu
if (!Device.SupportsAdvancedMenus && State.Menu.LayerInfo != LayerTypes.NetworkTop)
{
NetworkMenuItem menuItem = new NetworkMenuItem(line, text);
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
State.Menu.Items.Add(menuItem);
});
OnMenuLoading(new MenuLoadingArgs(menuItem));
}
}
// C - Track Cursor
if (parameters.Substring(0,1) == "C")
{
if (parameters.Substring(1, 1)== "-")
{
// No Cursor
// Sent when entering player screen
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
...
State.Menu.Items.Clear();
OnMenuTitleInfoChanged(new MenuTitleInfoChangedArgs(State.Menu));
}
}
});
}
Like this it would just jump over the dispatcher for no apparent reason. If I put the entire thing in a single dispatcher it works fine.
A second question, if I have another event with a dispatcher, something like this:
foreach (xxx)
{
if (xxx == yyy)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
State.Menu.Items.Add(menuItem);
});
}
}
Would it be preferable to instead wrap the entire foreach loop in a dispatcher rather then calling it when needed each iteration?
Since my original question has changed I've made a new post with more specifics and another possible solution by just wrapping the original socket listener task in a dispatcher
Possible solution to issue with multiple UI dispatchers in the same method?
*** Update:
I think Raymond is on the right track, though adding Task didn't fix it, I noticed although it starts processing line "0" of the menu, before it sets up the new menu it tries to process the next line "1" command which is ignored because it doesn't have the right menu state yet, it still hasn't been set by the previous command yet.
I'm not sure how to fix it, it seems like I have to do an await at a lower level so be sure sure it full finishes one command before starting the next (and not sure why putting the whole ProcessNLS in UI dispatcher works), it's a little complicated since I go through multiple levels but here is the flow:
socket = new StreamSocket();
try
{
await socket.ConnectAsync(new HostName(HostName), Port);
OnConnect(new EventArgs());
await Task.Factory.StartNew(WaitForMessage);
}
catch (Exception ex)
{
OnConnectionFail(new EventArgs());
}
Goes to:
private async void WaitForMessage()
{
...
foreach (var message in messages)
{
if (string.IsNullOrWhiteSpace(message))
continue;
ProcessMessage(message);
}
}
Goes to
private void ProcessMessage(string message, string optionalFlags = "")
{
...
case "NLS": // NET/USB List Info
ProcessNLS(parameters);
break;
}
to finally
private async void ProcessNLS(string parameters) // NET/USB List Info
My alternate solution is to put to ProcessMessage call under WaitForMessage in a UI dispatcher
*** Update #2
I think this may be working, here is the updated flow, have to await multiple steps, use task instead of void
private async void WaitForMessage()
{
...
foreach (var message in messages)
{
if (string.IsNullOrWhiteSpace(message))
continue;
await ProcessMessage(message);
}
}
}
catch (Exception ex)
{
Debug.WriteLine("WaitForMessage Error: " + ex.Message);
OnDisconnect(new EventArgs());
}
}
to
private async Task ProcessMessage(string message, string optionalFlags = "")
{
...
case "NLS": // NET/USB List Info
await ProcessNLS(parameters);
break;
}
to
private async Task ProcessNLS(string parameters) // NET/USB List Info
The problem is here:
private async void ProcessNLS(...)
^^^^^^^^^^
You declared an async void function, which means "When the first await happens, return from the function immediately, and let the rest of the work run asynchronously." If you want the caller to be able to await on completion of your function, change the signature to private async Task ProcessNLS(...).

Categories

Resources