Windows Phone Periodic Task Synchronization Async Methods - c#

I am attempting to make use of a Periodic Background Task on a Windows Phone 8 app. I want to use a xml file to serialize state information between the foreground app and the background task.
I read that you should use a Mutex to synchronize access to the file. However, I run into issues using it, because I need to call await in the method that I use the Mutex in (to read and write data to a file). This causes my app to lock up when I call Mutex.Release, since it is being released on a different thread. Any ideas how to handle this?
public async Task WriteState(BackgroundTaskState state)
{
using (var m = new Mutex(false, BackgroundTaskState.MutexName))
{
try
{
m.WaitOne();
using (var stream = await GetFileStreamForWriting())
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(BackgroundTaskState));
xmlSerializer.Serialize(stream, state);
await stream.FlushAsync();
}
}
catch (Exception)
{
}
finally
{
m.ReleaseMutex();
}
}
}

A Mutex must only be released by the same thread that acquired it so you cannot using it with await. You can use Semaphore to achieve the same result, since they are not bounded to ant particular thread.
semaphore.WaitOne();
await Task.Delay(2); // Your async call
semaphore.Release();

Related

Why is this MVC method not running in parallel manner?

Background
I have an MVC 5 application and wanted to test if the requests were running in parallel. To do so I used the code below, and opened multiple pages all making the same request.
Code
Below is a relatively simple method where I wanted to the parallel nature.
public async Task<ActionResult> Login(string returnUrl, string message = "")
{
var rng = new Random();
var wait = rng.Next(3, 10);
var threadGuid = Guid.NewGuid();
DebugHelper.WriteToDebugLog($"Thread {threadGuid} about to wait {wait} seconds");
await Task.Delay(wait * 1000);
DebugHelper.WriteToDebugLog($"Thread {threadGuid} finished");
return View();
}
The class DebugHelper is just used so that I can write to a file safely.
public static class DebugHelper
{
private static readonly object WriteLock = new object();
public static void WriteToDebugLog(string message, string path = "C:\\Temp\\Log.txt")
{
lock (WriteLock)
{
File.AppendAllLines(path, new string[] { "", GetDateString(), message });
}
}
}
Output
I'm consistently getting this type of output which suggests the threads are blocking each other.
2020-03-24T13:43:43.1431913Z
Thread 6e42a6c5-d3cb-4541-b8aa-34b290952973 about to wait 7 seconds
2020-03-24T13:43:50.1564077Z
Thread 6e42a6c5-d3cb-4541-b8aa-34b290952973 finished
2020-03-24T13:43:50.1853278Z
Thread 90923f55-befd-4224-bdd8-b67f787839fc about to wait 4 seconds
2020-03-24T13:43:54.1943271Z
Thread 90923f55-befd-4224-bdd8-b67f787839fc finished
2020-03-24T13:43:54.2312257Z
Thread fa2d8d30-b762-4262-b188-0b34da5f4f04 about to wait 3 seconds
2020-03-24T13:43:57.2370556Z
Thread fa2d8d30-b762-4262-b188-0b34da5f4f04 finished
2020-03-24T13:43:57.2679690Z
Thread 37311a0e-d19e-4563-b92a-5e5e3def379a about to wait 8 seconds
2020-03-24T13:44:05.2812367Z
Thread 37311a0e-d19e-4563-b92a-5e5e3def379a finished
Question
Why is this occurring?
I was under the impression that any ASP.NET application was multithreaded to begin with, so even in a situation where I don't have the async/await setup, I thought it would run these threads simultaneously.
Update
As suggested in the answers/comments, my methodology was wrong. After using the following code I could see quite clearly in the logs that it was indeed running in parallel.
var targetTime = DateTime.UtcNow + TimeSpan.FromSeconds(5);
while(DateTime.UtcNow < targetTime)
{
DebugHelper.WriteToDebugLog($"Thread {threadGuid} with ID {threadId} doing stuff");
await Task.Delay(1000);
}
It simply boils down to the fact that your debug logging with its WriteLock and synchronous File.AppendAllLines forces a synchronization lock onto all asynchronous functions that call it.
You would do far better to have an asynchronous write to debug process that would allow your tasks to continue running.
Product/consumer patter, semaphores, events, use of asynchronous file access APIs all spring to mind.
If you are using session at all it can lock the user to a single thread. Check for controller level, page level, or filter/attribute session use. If you are unsure try adding
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
to the controller.
Also, await by default will continue on the same thread that began the await. Try using configureAwait(false) to allow it to be flexible in the threads it uses.
await Task.Delay(wait * 1000).ConfigureAwait(false);

Limiting concurrent async tasks

I want to upload potentially large batches (possibly 100s) of files to FTP, using the SSH.NET library and the Renci.SshNet.Async extensions. I need to limit the number of concurrent uploads to five, or whatever number I discover the FTP can handle.
This is my code before any limiting:
using (var sftp = new SftpClient(sftpHost, 22, sftpUser, sftpPass))
{
var tasks = new List<Task>();
try
{
sftp.Connect();
foreach (var file in Directory.EnumerateFiles(localPath, "*.xml"))
{
tasks.Add(
sftp.UploadAsync(
File.OpenRead(file), // Stream input
Path.GetFileName(file), // string path
true)); // bool canOverride
}
await Task.WhenAll(tasks);
sftp.Disconnect();
}
// trimmed catch
}
I've read about SemaphoreSlim, but I don't fully understand how it works and how it is used with TAP. This is, based on the MSDN documentation, how I would implement it.
I'm unsure if using Task.Run is the correct way to go about this, as it's I/O bound, and from what I know, Task.Run is for CPU-bound work and async/await for I/O-bound work. I also don't understand how these tasks enter (is that the correct terminology) the semaphore, as all they do is call .Release() on it.
using (var sftp = new SftpClient(sftpHost, 22, sftpUser, sftpPass))
{
var tasks = new List<Task>();
var semaphore = new SemaphoreSlim(5);
try
{
sftp.Connect();
foreach (var file in Directory.EnumerateFiles(localPath, "*.xml"))
{
tasks.Add(
Task.Run(() =>
{
sftp.UploadAsync(
File.OpenRead(file), // Stream input
Path.GetFileName(file), // string path
true)); // bool canOverride
semaphore.Release();
});
}
await Task.WhenAll(tasks);
sftp.Disconnect();
}
// trimmed catch
}
from what I know, Task.Run is for CPU-bound work
Correct.
and async/await for I/O-bound work.
No. await is a tool for adding continuations to an asynchronous operation. It doesn't care about the nature of what that asynchronous operation is. It simply makes it easier to compose asynchronous operations of any kind together.
If you want to compose several asyncrhonous operations together you do that by making an async method, using the various asynchronous operations, awaiting them when you need their results (or for them to be completed) and then use the Task form that method as its own new asynchronous operation.
In your case your new asynchronous operation simply needs to be awaiting the semaphore, uploading your file, then releasing the semaphore.
async Task UploadFile()
{
await semaphore.WaitAsync();
try
{
await sftp.UploadAsync(
File.OpenRead(file),
Path.GetFileName(file),
true));
}
finally
{
semaphore.Release();
}
}
Now you can simply call that method for each file.
Additionally, because this is such a common operation to do, you may find it worth it to create a new class to handle this logic so that you can simply make a queue, and add items to the queue, and have it handle the throttling internally, rather than replicating that mechanic everywhere you use it.

When to use Task.Run and not

I asked this question yesterday and still don't understand the difference in using
task = Task.Run(() => RunLongRunningMethod(cts.Token));
and
task = RunLongRunningMethod(cts.Token);
I've read through Task.Run Etiquette and Proper Usage and it appears to be mostly using Task.Run as long as it's used correctly (not in the implementation)
Is there any other reading material about this and or can someone explain the difference between the two?
My code is below which works okay using both methods.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private static HttpClient client { get; set; }
private Task task { get; set; }
private CancellationTokenSource cts { get; set; }
private bool buttonStartStopState { get; set; }
public Form1()
{
InitializeComponent();
}
private async Task RunLongRunningMethod(CancellationToken cancellationToken)
{
try
{
while (true)
{
if (cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
}
// Some CPU bound work here
// Then call async
var success = await GetUrlAsync(#"https://www.bbc.co.uk/");
Thread.Sleep(2000); // simulate blocking only
}
}
catch (OperationCanceledException)
{
// Just exit without logging. Operation cancelled by user.
}
catch (Exception ex)
{
// Report Error
}
}
private async Task<bool> GetUrlAsync(string url)
{
if (client == null)
{
client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true, AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip });
client.BaseAddress = new Uri("https://www.bbc.co.uk/");
client.DefaultRequestHeaders.Add("Accept", "*/*");
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/62.0");
client.DefaultRequestHeaders.Connection.Add("Keep-Alive");
client.DefaultRequestHeaders.Add("DNT", "1");
}
var response = await client.GetAsync(url);
var contents = await response.Content.ReadAsStringAsync();
Debug.WriteLine($"{DateTime.Now} {response.StatusCode}");
return true;
}
private void buttonStartStop_Click(object sender, EventArgs e)
{
buttonStartStopState = !buttonStartStopState;
if(buttonStartStopState)
{
cts = new CancellationTokenSource();
// What is difference between this
//task = Task.Run(() => RunLongRunningMethod(cts.Token));
// And this?
task = RunLongRunningMethod(cts.Token);
// This always runs instantly
Debug.WriteLine($"{DateTime.Now} buttonStartStopState:{buttonStartStopState}");
}
else
{
cts.Cancel();
cts = null;
}
}
private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if(cts != null)
{
cts.Cancel(); // CancellationTokenSource
cts = null;
}
if (!task.IsCompleted)
{
//this.Hide();
e.Cancel = true;
await task;
this.Close();
}
}
}
}
Basically, use async/await throughout your code base so that nothing is blocking threads. (e.g. your current use of Thread.Sleep is blocking, as I commented).
Once you've reached that point, you've already got hot Tasks returned by your async functions, and these functions will return as soon as they're not making further progress.
At this point, you have a decision to make. Do you have a long running task that is CPU bound? If so, that is when you might consider using Task.Run, because that explicitly asks for the work to be done elsewhere (the thread pool). It's generally ok to allow I/O dominated tasks to come back onto the UI thread briefly, which is what you'll get by default and means that you don't have to do anything special to access UI objects.
Hopefully, at this point, you'll not want to use Task.Run at all in your example.
But it is possible that your long running task is a combination of truly async I/O operations and some CPU intensive operations, and you still don't want those occupying the UI thread. At this point, you should normally be considering using ConfigureAwait(false) on your awaitables. But you may wish to also use Task.Run here.
In either case, if you're wanting to interact with UI objects again, you'll have to Invoke to get back onto the UI thread. Make sure you do this at the right "granularity". Don't Invoke 5 or 6 separate basic setting of properties on UI objects. But also don't Invoke back onto the UI thread before actually doing the CPU intensive operations - they're why you tried to move them to a different thread in the first place!
Just to add to the 2 previous answers
Answer by #Neil
Answer by #Thierry V
It looks like you are running inside WinForms which runs in STA (Single Threaded Apartment) model, meaning there is only thread processing UI queued messages.
Therefore when you run task = Task.Run(() => RunLongRunningMethod(cts.Token)); this does everything on a thread pool thread, where as by default the task = RunLongRunningMethod(cts.Token); will block the UI for the duration of Thread.Sleep(2000); // simulate blocking only as your await call will be queued onto the the UI Dispatcher as you do not have ConfigureAwait(false).
Overall not running it on a background thread means:
Your Thread.Sleep(x) or the actual work time taken will block the UI
You will put more pressure on the dispatcher as each await will be scheduled to be executed by the UI dispatcher. (in your instance if it is only a single await, it is not an issue, but if you started to do 100's or even 1000's awaits, this can start showing noticeable performance loss!)
task = Task.Run(() => RunLongRunningMethod(cts.Token));
Will queue RunLongRunningMethod to be executed by one of the threads in the task pool at some point in the future. The next line of code will be executed immediately.
Whereas
RunLongRunningMethod(cts.Token);
Will execute the code on the current thread, and will not run the next line of code until it has finished.
RunLongRunningMethod(cts.Token); execute your action immediately in the same thread. That means it can block your UI if your code is in the UI thread.
task = Task.Run(() => RunLongRunningMethod(cts.Token)); contrariwise means that you want to execute right away your action. This line queues the task to run on the ThreadPool and returns a task handle for that work.
Normally, we use:
Task.Run when you want to execute a long-running code and don't wait if the task finishes. a calculation in background i.e and
task = RunLongRunningMethod normally when you want to await task, i.e
await RunLongRunningMethod(token);
//this method DoSomeThing is not executed until your your long-running code finishs
DoSomeThing();

TPL inside Windows Service

I need to perform few tasks inside a Windows Service I am writing in parallel. I am using VS2013, .NET 4.5 and this thread Basic design pattern for using TPL inside windows service for C# shows that TPL is the way to go.
Below is my implementation. I was wondering if anyone can tell me if I have done it correctly!
public partial class FtpLink : ServiceBase
{
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private readonly ManualResetEvent _runCompleteEvent = new ManualResetEvent(false);
public FtpLink()
{
InitializeComponent();
// Load configuration
WebEnvironment.Instance.Initialise();
}
protected override void OnStart(string[] args)
{
Trace.TraceInformation("DatabaseToFtp is running");
try
{
RunAsync(_cancellationTokenSource.Token).Wait();
}
finally
{
_runCompleteEvent.Set();
}
}
protected override void OnStop()
{
Trace.TraceInformation("DatabaseToFtp is stopping");
_cancellationTokenSource.Cancel();
_runCompleteEvent.WaitOne();
Trace.TraceInformation("DatabaseToFtp has stopped");
}
private async Task RunAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Trace.TraceInformation("Working");
// Do the actual work
var tasks = new List<Task>
{
Task.Factory.StartNew(() => new Processor().ProcessMessageFiles(), cancellationToken),
Task.Factory.StartNew(() => new Processor().ProcessFirmware(), cancellationToken)
};
Task.WaitAll(tasks.ToArray(), cancellationToken);
// Delay the loop for a certain time
await Task.Delay(WebEnvironment.Instance.DatabasePollInterval, cancellationToken);
}
}
}
There are a few things i would do differently:
OnStart should execute in a timely fashion. Common practice is to defer work to a background thread which is in charge of doing the actual work. You're actually doing that but blocking that thread with a call to Task.Wait, which kind of makes the offloading to a background thread useless, because execution becomes synchronous again.
You're using the sync over async anti-pattern, this should be mostly avoided. Let the calling method invoke the work in parallel.
I think you might be using the ManualResetEvent the other way around. You're wrapping your RunAsync method in a try-finally block, but you're only calling WaitOne from OnStop. I'm not really sure you need a lock here at all, it doesn't seem (from your current code) that this code is being invoked in parallel. Instead, you can store the Task returned by RunAsync in a field and wait on it to complete.
You're using the blocking version, WaitAll. Instead, you could use the asynchronous version, Task.WhenAll, which can be asynchronously waited.

Set thread lifetime at startup

Is there a way to set a value for how long a thread should (maximally) be alive when you start the thread?
Said in another way, with "pseudocode", is there anything like this:
Thread t = new Thread();
t.start();
t.abort_after_x_seconds(30);
which would make the thread abort if it lived more than 30 seconds.
Edit: I still can't get it to work, what I originally had is:
while(true)
{
if(...)
{
Thread t = new Thread(new ThreadStart(startMethod));
t.start();
}
Thread.sleep(...);
}
the problem is that sometimes the threads will hang (I'm not implementing what the threads do so I don't know exactly why (it's a school project, we're noobs at organizing)), so I want to kill those threads. I tried using Tasks and CancellationTokens as in the examples below, but when the Task hangs
it can't check if a cancellation request has occured.
Most of the time, you shouldn't be using Threads, use Tasks instead. They are more convenient and more efficient.
Aborting something is not safe, you should use cooperative cancellation instead. If you're calling a method that supports cancellation, then just pass it a cancellation token that will be cancelled after 30 seconds.
So your code could look like this (using .Net 4.5):
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)));
var task = Task.Run(() => YourMethod(cts.Token), cts.Token);
[EDIT: My response was far too slow. But I'll leave this here for the sample code.]
You should use co-operative cancellation for this purpose. The thread itself will need to detect when it should exit, and respond appropriately.
There's a thing called a CancellationToken produced from a CancellationTokenSource that you can use for this purpose.
There's even a CancellationTokenSource constructor which lets you set a timeout.
Here's some sample code to demonstrate its use:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
class Program
{
private void run()
{
using (var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
{
var task = Task.Run(() => exampleOne(tokenSource.Token));
task.Wait();
}
using (var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
{
var task = Task.Run(() => exampleTwo(tokenSource.Token));
task.Wait();
}
Console.WriteLine("Done.");
}
static void exampleZero()
{
Console.WriteLine("Starting exampleZero()");
try
{
Thread.Sleep(10000); // Simulate work.
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation cancelled.");
}
Console.WriteLine("Exiting exampleZero()");
}
static void exampleOne(CancellationToken cancellation)
{
Console.WriteLine("Starting exampleOne()");
// Busy loop processing.
while (!cancellation.IsCancellationRequested)
{
// Do some work.
}
Console.WriteLine("Exiting exampleOne()");
}
static void exampleTwo(CancellationToken cancellation)
{
Console.WriteLine("Starting exampleTwo()");
while (!cancellation.WaitHandle.WaitOne(100)) // Wait 100ms between work.
{
// Do some work.
}
Console.WriteLine("Exiting exampleTwo()");
}
static void Main()
{
new Program().run();
}
}
}
As commenters have said, using Abort is bad practice and not guaranteed to abort immediately.
Why would you want to keep the thread alive? The thread will be released back to the pool when the task assigned to it is completed. The next time the task is run on the thread will automatically be given from the pool of threads either by creating another new one or re-using one that is available in the threadpool.
Sounds like your logic/code is bad and needs to be fixed rather than waiting for something for x seconds then terminating it, which in itself will cause knock on problems.
Perhaps you need a timer instead which can tick after 30 seconds then you can disable the timer and kill the task at hand.

Categories