static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(o => DoWork(cts.Token, 100));
Thread.Sleep(500);
try
{
cts.Token.Register(CancelCallback3);
cts.Token.Register(CancelCallback2);
cts.Token.Register(CancelCallback1);
cts.Cancel(false);
}
catch (AggregateException ex)
{
foreach (Exception curEx in ex.Data)
{
Trace.WriteLine(curEx.ToString());
}
}
Console.ReadKey();
}
private static void CancelCallback1()
{
Trace.WriteLine("CancelCallback1 was called");
throw new Exception("CancellCallback1 exception");
}
private static void CancelCallback2()
{
Trace.WriteLine("CancelCallback2 was called");
throw new Exception("CancellCallback2 exception");
}
private static void CancelCallback3()
{
Trace.WriteLine("CancelCallback3 was called");
}
private static void DoWork(CancellationToken cancellationToken, int maxLength)
{
int i = 0;
while (i < maxLength && !cancellationToken.IsCancellationRequested)
{
Trace.WriteLine(i++);
Thread.Sleep(100);
}
}
The output is:
0
1
2
3
4
CancelCallback1 was called
According to http://msdn.microsoft.com/en-us/library/dd321703.aspx I expected to get AggregateException, it looks like that throwOnFirstException parameter doesn't make any sense here. What's wrong with my code.
You need to use the Task<> class to get an AggregateException. It is a substitute for ThreadPool.QueueUserWorkItem().
The problem is with lack of strong debugging experience in Visual Studio. My VS debugger settings were set to stop at first exception occurence.
FYI CancellationTokenSource.Cancel(false) works fine with ThreadPool as well as with Tasks.
Related
I wonder why SpinLock doesn't support recursion.
Let's say I have a simple program with Monitor that locks and releases a block of instructions in a recursive way:
class Program
{
private static readonly object lockObj = new object();
private static void Recursion(int x)
{
bool lockWasTaken = false;
try
{
Monitor.Enter(lockObj, ref lockWasTaken);
Console.WriteLine(x);
}
finally
{
if (x > 0)
{
Recursion(x - 1);
}
if (lockWasTaken) Monitor.Exit(lockObj);
}
}
static void Main(string[] args)
{
Recursion(5);
Console.ReadKey();
}
}
If I do the same with SpinLock:
class Program
{
private static SpinLock sl = new SpinLock(true);
private static void Recursion(int x)
{
bool lockWasTaken = false;
try
{
sl.Enter(ref lockWasTaken);
Console.WriteLine(x);
}
finally
{
if (x > 0)
{
Recursion(x - 1);
}
if (lockWasTaken) sl.Exit();
}
}
static void Main(string[] args)
{
Recursion(5);
Console.ReadKey();
}
}
It throws an excpetion which says the calling thread already has a lock - and it is obviously true.
But my question is why Monitor can acquire a lock multiple times by the same thread while SpinLock cannot?
I can't find any reasons why a thread that has already locked a critical section can't enter it again.
How can I implement a timeout for a potentially long running action lambda? I have tried wrapping the action in a Task and then using a cancellation token to enforce the timeout but to no avail.
public void LongRunningTask()
{
ExecuteSafely(() => //do something );
}
private void ExecuteSafely(Action action)
{
try
{
action();
}
catch
{
// just don't crash
}
}
New implementation as per 1st answer:
public void Information<T>(string messageTemplate, T propertyValue)
{
ExecuteSafely(() => _logger.Information(messageTemplate, propertyValue));
}
private void ExecuteSafely(Action action)
{
try
{
var cts = new CancellationTokenSource();
cts.CancelAfter(new TimeSpan(0, 0, 1));
try
{
Task.Run(action, cts.Token).Wait();
}
catch (TaskCanceledException e)
{
System.Diagnostics.Debug.WriteLine(e.ToString());
//here you know the task is cancelled due to timeout
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.ToString());
// just don't crash
}
}
This is only working correctly when I step into Task.Run but not when I step over or let it run. Perhaps there is some closure issue with the lambda being passed into the action?
You should use CancellationTokenSource
void Execute(Action action, TimeSpan timeout)
{
var cts = new CancellationTokenSource();
cts.CancelAfter(timeout);
try
{
Task.Run(action, cts.Token).Wait();
}
catch (TaskCanceledException e)
{
//here you know the task is cancelled due to timeout
}
}
For some reason I could not catch an exception thrown inside anonymous async delegate that subscribed to event.
It does not get caught inside TestTestAsync (I suppose because of invoke wait only fastest one) but why it is not caught in unhandled or unobserved or crash app?
ThrowUnobservedTaskExceptions = true also does not make any sense.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp5
{
class Program
{
static string lockStr = Guid.NewGuid().ToString();
public static void ConsoleWriteLine(string Message, ConsoleColor? color = null)
{
lock (lockStr)
{
var old = Console.ForegroundColor;
if (color != null)
Console.ForegroundColor = color.Value;
Console.WriteLine(Message);
if (color != null)
Console.ForegroundColor = old;
}
}
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
try
{
var cls = new TestClass();
cls.TestAsync += async (s) => await Cls_TestRealAsyncAsync(s);
cls.TestAsync += Cls_TestRealAsync;
Task.Run(async () => await cls.TestTestAsync()).Wait();
Thread.Sleep(5000);
}
catch (Exception ex)
{
ConsoleWriteLine($"{nameof(Main)}: {ex.Message}");
}
}
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
ConsoleWriteLine($"{nameof(TaskScheduler_UnobservedTaskException)}: {(e.Exception as Exception).Message}", ConsoleColor.Yellow);
}
private static Task Cls_TestRealAsync(object sender)
{
try
{
Thread.Sleep(100);
throw new NotImplementedException($"{nameof(Cls_TestRealAsync)}");
}
catch (Exception ex)
{
ConsoleWriteLine(ex.Message, ConsoleColor.Red);
throw;
}
}
private static async Task Cls_TestRealAsyncAsync(object sender)
{
try
{
await Task.Run(() => Thread.Sleep(1000));
throw new NotImplementedException($"{nameof(Cls_TestRealAsyncAsync)}");
}
catch (Exception ex)
{
ConsoleWriteLine(ex.Message, ConsoleColor.Red);
throw;
}
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ConsoleWriteLine($"{nameof(CurrentDomain_UnhandledException)}: {(e.ExceptionObject as Exception).Message}", ConsoleColor.Yellow);
}
}
public class TestClass
{
public delegate Task TestHandlerAsync(object sender);
public event TestHandlerAsync TestAsync;
private async Task OnTestAsync()
{
if (TestAsync != null)
await TestAsync.Invoke(this);
}
public async Task TestTestAsync()
{
try
{
await OnTestAsync();
}
catch (Exception ex)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {ex.Message}", ConsoleColor.Green);
}
}
}
}
PS: I made tests on 4.7.1
Asynchronous code is not necessarily concurrent code, but you should be careful anyway.
This:
private async Task OnTestAsync()
{
if (TestAsync != null)
await TestAsync.Invoke(this);
}
can get you in trouble because by the time TestAsync.Invoke is invoked, TestAsync can be null.
But the problem that you're trying to solve is that, not the that the fastest one is awaited but that the last one is awaited.
You should revise your API but, if you can't, try this:
public class TestClass
{
public delegate Task TestHandlerAsync(object sender);
public event TestHandlerAsync TestAsync;
private async Task OnTestAsync()
{
var testAsync = this.TestAsync;
if (testAsync == null)
{
return;
}
await Task.WhenAll(
from TestHandlerAsync d in testAsync.GetInvocationList()
select d.Invoke(this));
}
public async Task TestTestAsync()
{
try
{
await OnTestAsync();
}
catch (Exception ex)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {ex.Message}", ConsoleColor.Green);
}
}
}
if you only care to show the first exception.
Or:
public class TestClass
{
public delegate Task TestHandlerAsync(object sender);
public event TestHandlerAsync TestAsync;
private async Task<Exception[]> OnTestAsync()
{
var testAsync = this.TestAsync;
if (testAsync == null)
{
return new Exception[0];
}
return await Task.WhenAll(
from TestHandlerAsync d in testAsync.GetInvocationList()
select ExecuteAsync(d));
async Task<Exception> ExecuteAsync(TestHandlerAsync d)
{
try
{
await d(this);
return null;
}
catch (Exception ex)
{
return ex;
}
}
}
public async Task TestTestAsync()
{
try
{
var exceptions = await OnTestAsync();
foreach (var exception in exceptions)
{
if (exception != null)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {exception.Message}", ConsoleColor.Green);
}
}
}
catch (Exception ex)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {ex.Message}", ConsoleColor.Green);
}
}
}
if you care for all.
Found the answer. It not abandoned. It simply still not fired because of life of my test console was too short.
Unhandled exception will be thrown at GC.Collect()
https://blogs.msdn.microsoft.com/ptorr/2014/12/10/async-exceptions-in-c/
During GC, it notices that nobody ever checked the result (and
therefore never saw the exception) and so bubbles it up as an
unobserved exception.
So next code before main method end will solve issue and I see exception
GC.Collect();
Thread.Sleep(5000);
I have a console app that instantiates a WeatherClientManager class.
The main thread in the console app requests current weather status in the WeatherClientManager class, but the WeatherClientManager class continuously receives data from a server.
In code:
public static void Main(string [])
{
Program p = new Program();
Task.Run(()=>p.RunLoop());
}
class Program{
WeatherClientManager wcM;
public void RunLoop()
{
wcM = new WeatherClientManager ();
await wcM.InitiateConnection().ConfigureAwait(false);
}
}
class WeatherClientManager
{
public async Task<bool> InitiateConnection()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync()
CancellationTokenSource cts = new CancellationTokenSource();
if(tcpClient.Connected)
{
Task.Run(()=>ReceiveTask(cts.Token));
Task.Run(()=>SendKeepAlive(cts.Token));
return true;
}
return false;
}
private void ReceiveTask(CancellationToken t)
{
try{
networkStream.Receive(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
private void SendKeepAlive(CancellationToken t)
{
while(!t.IsCancellationRequested)
{
try{
networkStream.Write(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
}
private void Stop(Exception e )
{
log.Error(e);
e.Cancel();
}
}
One of many crap ideas I have is:
Task.Run( () =>
{
while(true)
{
var t1 = Task.Run(()=>ReceiveTask(cts.Token));
var t2= Task.Run(()=>SendKeepAlive(cts.Token));
try{
Tasks.WhenAny(); // should block
}
catch(Exception e)
{
}
finally{
Cleanup();
InitiateConnections();
}
}
}
But I hate the idea of spinning a task to control two sub tasks. My problem is where and how to re-initiate the connection. Any ideas?
EDIT:
I've updated the code such that WeatherClientManager has a OnDisconnectDetected event. So the Program.cs class subscribes like so:
weatherServerManager.OnDisconnectDetected += HandleDisconnectDetection
public async void HandleDisconnectDetection()
{
wsM = new WeatherClientManager ();
wsM.InitiateConnection().ConfigureAwait(false);
}
private void SendKeepAlive(CancellationToken t)
{
while (...)
{
try{}
catch(Exception e)
{
OnDisconnectDetected?.Invoke();
}
}
}
When the handler is invoked by the WeatherClientManager it creates a new task that should continue in a different context. The KeepAlive task should exit then.
Still feels hacky but ideas welcome!
As a general rule, I prefer composition of methods over raising events. In particular, avoid the Task.Run-based fire-and-forget.
In the case of asynchronous sockets, I think it makes sense to give each socket a main loop:
class WeatherClientManager
{
public async Task MainLoop()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync();
CancellationTokenSource cts = new CancellationTokenSource();
var receiveTask = Task.Run(()=>ReceiveTask(cts.Token));
var keepaliveTask = Task.Run(()=>SendKeepAlive(cts.Token));
await Task.WhenAll(receiveTask, keepaliveTask);
}
}
These can then be composed into the main program's main loop:
class Program
{
public async Task RunLoop()
{
while (true)
{
wcM = new WeatherClientManager();
await wcM.MainLoop();
}
}
}
which in turn is composed into Main:
public static void Main(string [])
{
Program p = new Program();
p.RunLoop().GetAwaiter().GetResult();
}
By avoiding fire-and-forget, you're ensuring that your code will always observe all exceptions. Ignoring tasks is occasionally okay but usually a mistake.
I find myself using async fire-and-forget methods using void as the return value, but DO care about exceptions.
It seems to be the consensus that exceptions cannot be handled properly with async-await if no reference is hold to the executing Task and void should be.. well.. avoided..
What am I missing in the following code that apparently seems to do the job:
class Program
{
static void Main()
{
var p = new Processor();
p.ExceptionThrown += p_ExceptionThrown;
for (var i = 0; i < 10; i++)
p.ProcessAsync(i);
Console.ReadKey();
}
static void p_ExceptionThrown(object sender, Exception e)
{
Console.WriteLine("Exception caught in Main : " + e);
}
}
class Processor
{
public async void ProcessAsync(int iteration)
{
try
{
await Task.Run(() => Process(iteration));
}
catch (Exception e)
{
OnException(e);
}
}
public void Process(int iteration)
{
Thread.Sleep(500);
if(iteration == 5)
throw new Exception("AUUCH");
}
public event EventHandler<Exception> ExceptionThrown;
void OnException(Exception e)
{
var handler = ExceptionThrown;
if (handler != null)
handler(this, e);
}
}
Under the covers the async / await keywords actually generate a state-machine when they are compiled down to IL, please read about it here. The only time that you should ever use async void is on an event handler, as explained here. The issue is that when the state machine is built-out it uses the Task or Task<T> classes as the return type in order to manage the next state of the next asynchronous operation in the chain. However, when you define the method as void, it basically returns null to the state machine and then everything gets out of whack.
Exceptions from an async void can’t be caught with catch
The quote from above is from the best practices article I pointed you to before. The below alteration does work, as I have tested it to verify that it does.
class Program
{
static void Main()
{
var p = new Processor();
p.ExceptionThrown += p_ExceptionThrown;
for (var i = 0; i < 10; i++)
p.ProcessAsync(i);
Console.ReadKey();
}
static void p_ExceptionThrown(object sender, Exception e)
{
Console.WriteLine("Exception caught in Main : " + e);
}
}
class Processor
{
public async Task ProcessAsync(int iteration)
{
try
{
await Task.Run(() => Process(iteration));
}
catch (Exception e)
{
OnException(e);
}
}
public void Process(int iteration)
{
Thread.Sleep(500);
if(iteration == 5)
throw new Exception("AUUCH");
}
public event EventHandler<Exception> ExceptionThrown;
void OnException(Exception e)
{
var handler = ExceptionThrown;
if (handler != null)
handler(this, e);
}
}