Read a lot of articles an watch many videos on Task Cancelation. But I still can't quite follow if it's possible to pass CancellationTokenSource instead of CancellationTokenSource providing that the condition required for a cancelation is being obtained inside of Task awaited?
protected CancellationTokenSource source = new CancellationTokenSource();
protected CancellationToken cancel_token => source.Token;
protected async Task FinishAsync(string message)
{
TimeSpan time = DateTime.Now - startTime;
if (GlobalVars.logger != null)
await GlobalVars.logger.LogDictionaryAsync("Elapsed " + Math.Round((time.TotalMilliseconds / 1000), 3).ToString() + "s " + "Token " + token + " " + user + " \n" + message, LogLevel.Reply, source );
cancel_token.ThrowIfCancellationRequested();
}
public async Task LogDictionaryAsync(string s, LogLevel logLevel = LogLevel.Info, string jobId = "", CancellationTokenSource source = null)
{
if (string.IsNullOrWhiteSpace(s))
return;
OpenStream();
await semaphore.WaitAsync();
if (string.IsNullOrWhiteSpace(s))
return;
try
{
byte[] bytes = Encoding.UTF8.GetBytes(LocalDate.ToString("dd/MM/yyyy H:mm:ss.FFF") + " " +
(!string.IsNullOrWhiteSpace(jobId) ? jobId : Thread.CurrentThread.ManagedThreadId.ToString().PadLeft(5, ' ')) + " " +
logLevel.ToString() + " " +
(s.Length <= MESSAGE_MAX_SIZE ? s : s.Substring(0, MESSAGE_MAX_SIZE) + "...(truncated)") +
"\n");
if (bytes.Length == 0)
{
source?.Cancel();
}
await fstream.WriteAsync(bytes, 0, bytes.Length);
fstream.Flush();
}
catch (AggregateException e)
{
throw e;
}
catch (Exception e)
{
Console.Write(e.Message);
}
finally
{
source?.Dispose();
semaphore.Release();
GC.Collect();
}
};
I call cancel_token.ThrowIfCancellationRequested() basing on the canceletion got in Task awaited.
Thank you Don't know exactly what is right
Cancelling the token source makes no sense if you already know you need to bail out. And you have a few issues with your code.
Firsty, you can pass the token without passing the whole source.
public async Task LogDictionaryAsync(string s, LogLevel logLevel = LogLevel.Info, string jobId = "",
CancellationToken token = default)
and
await GlobalVars.logger.LogDictionaryAsync(
$"Elapsed { Math.Round((time.TotalMilliseconds / 1000), 3)}s Token {token} {user} \n{message}",
LogLevel.Reply, source.Token);
You need to pass the token in various places inside that function, otherwise it won't work, as cancellation is cooperative.
Note that you should never acquire a semaphore and then dump it without releasing it.
if (string.IsNullOrWhiteSpace(s))
return;
await semaphore.WaitAsync(token);
try
{
byte[] bytes = Encoding.UTF8.GetBytes(
$"{LocalDate:dd/MM/yyyy H:mm:ss.FFF} {
(!string.IsNullOrWhiteSpace(jobId) ? jobId : Thread.CurrentThread.ManagedThreadId.ToString()), 5
} {logLevel} {
(s.Length <= MESSAGE_MAX_SIZE ? s : s.Substring(0, MESSAGE_MAX_SIZE) + "...(truncated)")
}\n");
if (bytes.Length == 0)
{
return;
}
await fstream.WriteAsync(bytes, 0, bytes.Length, token);
await fstream.FlushAsync(token);
}
catch (Exception e)
{
Console.Write(e.Message);
}
finally
{
semaphore.Release();
}
Note also the use of string formatting to make this more concise.