C# Check folder avoid blocking UI - c#

This is my code in order to check if a directory exists. As the directory might be also a network folder, I put a timeout. The code works but it blocks my UI:
private delegate bool DirectoryExistsDelegate(string folder);
public static bool DirectoryExists(string path, int timeout = 2000)
{
bool retValue = false;
try
{
DirectoryExistsDelegate callback = new DirectoryExistsDelegate(Directory.Exists);
IAsyncResult result = callback.BeginInvoke(path, null, null);
if (result.AsyncWaitHandle.WaitOne(timeout, false))
return callback.EndInvoke(result);
return false;
}
catch
{
return false;
}
}
How to solve this?

Your method doesn't return until the Exists call is fully complete, so it will always block the UI. You've essentially started an asynchronous operation, but then sit around twiddling your thumbs waiting for it to complete.
As Dmitry Bychenko pointed out, you can do this in another thread and handle it very cleanly using async, await and Task.Run. To do this you should also make the event handler that's calling this method async, e.g.:
// An async event handler
public async void Button_Click(...)
{
...
var exists = await DirectoryExists(myPath);
...
}
public async Task<bool> DirectoryExists(string path)
{
return await Task.Run<bool>(() => Directory.Exists(path));
}

Related

Async function not launching asynchronously

I still meet issues calling async functions.
In that code, I execute generateAllIfcs(dataFolder), then I would like to execute already addToExistingContract() or this.importNewContract() depending on contexte.SourceContract.
But this line is not reached until generateAllIfcs(dataFolder) is finished.
private async void Import(object sender, RoutedEventArgs e)
{
Task<bool> successGenerateIfc = this.generateAllIfcs(dataFolder);
Task<bool> successAddContractToVsteel = contexte.SourceContract != null ?
this.addToExistingContract() : this.importNewContract();
await Task.WhenAll(successGenerateIfc, successAddContractToVsteel);
}
private async Task<bool> generateAllIfcs(string dataFolder)
{
try
{
var progressIndicator4 = new Progress<int>(contexte.ReportProgress4);
if (contexte.SourceContract != null)
{
int total4 = await contexte.NewModel.ExportNewIfcContract(
contexte.SourceContract, progressIndicator4, 0, 100,
contexte.SelectedConfigImportIFC, true,dataFolder);
}
else
{
int total4 = await contexte.NewModel.ExportNewIfcContract(null,
progressIndicator4, 0, 100, contexte.SelectedConfigImportIFC,
true, dataFolder);
}
return true;
}
catch
{
return false;
}
}
public async Task<int> ExportNewIfcContract(Contract existingContract,
IProgress<int> progress, int startProgress, int endProgress,
ConfigImportIFC config, bool generateIfcAssAndRep, string dataFolder)
{
int retour = await this.exportNewIfcContract(existingContract, progress,
startProgress, endProgress,config, generateIfcAssAndRep, dataFolder);
return retour;
}
private async Task<int> exportNewIfcContract(Contract existingContract,
IProgress<int> progress, int startProgress, int endProgress,
ConfigImportIFC config, bool generateIfcAssAndRep, string dataFolder)
{
//some other calls to async functions
}
"async function not launching asynchronously" - yes, that's normal; async isn't about how things launch, it is about how they complete (or at least, continue); async doesn't mean "parallel", "concurrent", etc - and has only tangential relationship to threading; an async method runs synchronously until the first incomplete await, i.e. where the thing being awaited did not itself finish synchronously. Only for an incomplete await does the async engine unroll itself and register a continuation. I don't see anything inherently truly async in your code, although to be fair: I can't see exportNewIfcContract.
If you want concurrency, consider Task.Run etc to invoke a second execution flow. Or alternatively, consider adding:
await Task.Yield();
at the top of generateAllIfcs (the method that you intend to run concurrently); Task.Yield() always returns in an incomplete state, pushing the rest of the work as a continuation onto the thread-pool.

Correct Way to do Task Synchronization?

Is what I'm doing below the correct/best way to accomplish this?
I have a window with a timer. Each time the timer ticks, I call the RunTask method shown below. Within RunTask, I call DoTheThing. DoTheThing may take a while to run, and may fail (it's a database update). I want to make sure that at any point in time, I only have one DoTheThing outstanding. I also want to make sure that I don't have a bunch of RunTask instances all queued and waiting for a lock to be released by the RunTask instance that is running DoTheThing.
public void RunTask()
{
bool canRunTask = true;
// Check if another instance of this method is currently executing. If so, do not execute the rest of this method
lock (this.runTaskLock)
{
if (this.isTaskRunning)
{
canRunTask = false;
}
else
{
this.isTaskRunning = true;
}
}
// Call DoTheThing if another instance is not currently outstanding
if (canRunTask)
{
try
{
Task task = new Task(() => DoTheThing());
task.Start();
}
catch (Exception ex)
{
// Handle the exception
}
finally
{
lock (this.runTaskLock)
{
this.isTaskRunning = false;
}
}
}
}
Because of the architecture of the program, I would rather put all of my thread synchronization within this method instead of enabling and disabling the timer.
By thinking about the problem slightly differently, it becomes a lot easier. Instead of firing a timer every x seconds, why not wait x seconds between invocations?
Now you can just run an async loop to do the scheduled work and save yourself a bunch of painful synchronization work.
async Task RunActionPeriodicallyAsync(Action action,
TimeSpan ts,
CancellationToken token = default(CancellationToken))
{
while(!token.IsCancellationRequested)
{
action();
await Task.Delay(ts, token);
//or alternatively (see comment below)
//var delayTask = Task.Delay(ts, token);
//action();
//await delayTask;
}
}
Now, just call RunActionPeriodicallyAsync once, and calls to its action will never overlap.
RunActionPeriodicallyAsync(() => DoSomething(), TimeSpan.FromSeconds(10))
You could overload this to take an async "action"... actually a Func<Task>...
async Task RunActionPeriodicallyAsync(Func<CancellationToken, Task> actionAsync,
TimeSpan ts,
CancellationToken token = default(CancellationToken))
{
while(!token.IsCancellationRequested)
{
await actionAsync(token);
await Task.Delay(ts, token);
//or alternatively (see comment below)
//await Task.WhenAll(actionAsync(token), Task.Delay(ts, token))
}
}
and use it:
RunActionPeriodicallyAsync(async cancTok => await DoSomethingAsync(cancTok),
TimeSpan.FromSeconds(10))
If you are worried about too much locking, you can do the following. You might miss a run if one task completes while the other is just at the check (marked), but you got rid of some locking and you will only need to lock when you set isTaskRunnung = true.
In Addition you need to mark your method as async so you can await the task.
public async Task RunTask()
{
bool canRunTask = true;
// Check if another instance of this method is currently executing. If so, do not execute the rest of this method
if (this.isTaskRunning)
{ // <-- ___MARK___
canRunTask = false;
}
else
{
lock (this.runTaskLock)
{
if (this.isTaskRunning)
{
canRunTask = false;
}
else
{
this.isTaskRunning = true;
}
}
}
// Call DoTheThing if another instance is not currently outstanding
if (canRunTask)
{
try
{
await Task.Run(() => DoTheThing());
}
catch (Exception ex)
{
// Handle the exception
}
finally
{
this.isTaskRunning = false;
}
}
}

How can I convert a function with a ref paramter to an async function?

I have the following function which I want to convert to an async / non locking function.
Here is the function in its currenc form:
private static void BlockForResponse(ref bool localFlag)
{
int count = 0;
while (!localFlag)
{
Thread.Sleep(200);
if (count++ > 50) // 200 * 50 = 10 seconds
{
//timeout
throw new TimeOutException();
}
}
}
here is my attempt:
private static async Task BlockForResponse(ref bool localFlag)
{
int count = 0;
while (!localFlag)
{
await Task.Delay(200);
if (count++ > 50) // 200 * 50 = 10 seconds
{
//timeout
throw new TimeOutException();
}
}
}
however I get a compile error saying that async functions cant have ref or out parameters. However this is the core functionality of the function.
Is it possible to convert it to an async function?
Explanation of code:
I must admit this is an odd piece of code, let me try an explain what its trying to do:
so there is a 3rd party dll which I need to use. Which provides me with services, I sadly have no control over this dll.
The way it works,
I call a command in the dll providing it a callback function which it calls once it has finished the task.
I can only move on to what I want to do once I have the result from that call. hence the need fro this function.
I make the call to the dll, providing it with a call back function:
private bool _commandFlag = false;
private bool _commandResponse;
public async Task ExecuteCommand(string userId, string deviceId)
{
var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
try
{
//execute command
if (link.Command(Commands.ConnectToDevice, CallBackFunction))
{
BlockForResponse(ref _commandFlag);
return; //Received a response
}
else
{ //Timeout Error
throw new ConnectionErrorException();
}
}
catch (Exception e)
{
throw e;
}
}
private void CallBackFunction(bool result)
{
_commandResponse = result;
_commandFlag = true;
}
The way it works, I call a command in the dll providing it a callback function which it calls once it has finished the task.
Then what you really want is to use TaskCompletionSource<T> to create a TAP method, something similar to this.
public static Task<bool> CommandAsync(this Link link, Commands command)
{
var tcs = new TaskCompletionSource<bool>();
if (!link.Command(command, result => tcs.TrySetResult(result)))
tcs.TrySetException(new ConnectionErrorException());
return tcs.Task;
}
With this extension method in place, your calling code is much cleaner:
public async Task ExecuteCommand(string userId, string deviceId)
{
var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
var commandResponse = await link.CommandAsync(Commands.ConnectToDevice);
}
The problem with combining async and ref is that code inside an async function can run even after the method returns. So, if you did something like:
async Task BlockForResponseAsync(ref bool localFlag)
{
while (!localFlag)
{
...
}
}
void SomeMethod()
{
bool flag = false;
BlockForResponseAsync(ref flag); // note: no await here
}
Then the local variable flag would stop existing after SomeMethod() returned, but BlockForResponseAsync(), which has a reference to that variable, could still be executing. This is why the above code won't compile.
Basically, what you need is a closure, and in C#, ref doesn't create closures, but lambdas do. This means you can write your method like this:
async Task BlockForResponseAsync(Func<bool> localFlagFunc)
{
while (!localFlagFunc())
{
...
}
}
And use it like this:
bool flag = false;
var task = BlockForResponseAsync(() => flag);
// other code here
flag = true;
await task; // to make sure BlockForResponseAsync() completed successfully
This way also indicates your intention better. ref usually means something like: "give me a variable with some value, and I will change that value", which is not what you want here. On the other hand Func<T> means "give me something that I can use retrieve some value, potentially multiple times".

How to wait for a single event in C#, with timeout and cancellation

So my requirement is to have my function wait for the first instance an event Action<T> coming from another class and another thread, and handle it on my thread, allowing the wait to be interrupted by either timeout or CancellationToken.
I want to create a generic function I can reuse. I managed to create a couple options that do (I think) what I need, but both seem more complicated than I'd imagine it should have to be.
Usage
Just to be clear, a sample use of this function would look like this, where serialDevice is spitting out events on a separate thread:
var eventOccurred = Helper.WaitForSingleEvent<StatusPacket>(
cancellationToken,
statusPacket => OnStatusPacketReceived(statusPacket),
a => serialDevice.StatusPacketReceived += a,
a => serialDevice.StatusPacketReceived -= a,
5000,
() => serialDevice.RequestStatusPacket());
Option 1—ManualResetEventSlim
This option isn't bad, but the Dispose handling of the ManualResetEventSlim is messier than it seems like it should be. It gives ReSharper fits that I'm accessing modified/disposed things within the closure, and it's genuinely hard to follow so I'm not even sure it's correct. Maybe there's something I'm missing that can clean this up, which would be my preference, but I don't see it offhand. Here's the code.
public static bool WaitForSingleEvent<TEvent>(this CancellationToken token, Action<TEvent> handler, Action<Action<TEvent>> subscribe, Action<Action<TEvent>> unsubscribe, int msTimeout, Action initializer = null)
{
var eventOccurred = false;
var eventResult = default(TEvent);
var o = new object();
var slim = new ManualResetEventSlim();
Action<TEvent> setResult = result =>
{
lock (o) // ensures we get the first event only
{
if (!eventOccurred)
{
eventResult = result;
eventOccurred = true;
// ReSharper disable AccessToModifiedClosure
// ReSharper disable AccessToDisposedClosure
if (slim != null)
{
slim.Set();
}
// ReSharper restore AccessToDisposedClosure
// ReSharper restore AccessToModifiedClosure
}
}
};
subscribe(setResult);
try
{
if (initializer != null)
{
initializer();
}
slim.Wait(msTimeout, token);
}
finally // ensures unsubscription in case of exception
{
unsubscribe(setResult);
lock(o) // ensure we don't access slim
{
slim.Dispose();
slim = null;
}
}
lock (o) // ensures our variables don't get changed in middle of things
{
if (eventOccurred)
{
handler(eventResult);
}
return eventOccurred;
}
}
Option 2—polling without a WaitHandle
The WaitForSingleEvent function here is much cleaner. I'm able to use ConcurrentQueue and thus don't even need a lock. But I just don't like the polling function Sleep, and I don't see any way around it with this approach. I'd like to pass in a WaitHandle instead of a Func<bool> to clean up Sleep, but the second I do that I've got the whole Dispose mess to clean up again.
public static bool WaitForSingleEvent<TEvent>(this CancellationToken token, Action<TEvent> handler, Action<Action<TEvent>> subscribe, Action<Action<TEvent>> unsubscribe, int msTimeout, Action initializer = null)
{
var q = new ConcurrentQueue<TEvent>();
subscribe(q.Enqueue);
try
{
if (initializer != null)
{
initializer();
}
token.Sleep(msTimeout, () => !q.IsEmpty);
}
finally // ensures unsubscription in case of exception
{
unsubscribe(q.Enqueue);
}
TEvent eventResult;
var eventOccurred = q.TryDequeue(out eventResult);
if (eventOccurred)
{
handler(eventResult);
}
return eventOccurred;
}
public static void Sleep(this CancellationToken token, int ms, Func<bool> exitCondition)
{
var start = DateTime.Now;
while ((DateTime.Now - start).TotalMilliseconds < ms && !exitCondition())
{
token.ThrowIfCancellationRequested();
Thread.Sleep(1);
}
}
The question
I don't particularly care for either of these solutions, nor am I 100% sure either of them are 100% correct. Is either one of these solutions better than the other (idiomaticity, efficiency, etc), or is there an easier way or built-in function to meet what I need to do here?
Update: Best answer so far
A modification of the TaskCompletionSource solution below. No long closures, locks, or anything required. Seems pretty straightforward. Any errors here?
public static bool WaitForSingleEvent<TEvent>(this CancellationToken token, Action<TEvent> onEvent, Action<Action<TEvent>> subscribe, Action<Action<TEvent>> unsubscribe, int msTimeout, Action initializer = null)
{
var tcs = new TaskCompletionSource<TEvent>();
Action<TEvent> handler = result => tcs.TrySetResult(result);
var task = tcs.Task;
subscribe(handler);
try
{
if (initializer != null)
{
initializer();
}
task.Wait(msTimeout, token);
}
finally
{
unsubscribe(handler);
// Do not dispose task http://blogs.msdn.com/b/pfxteam/archive/2012/03/25/10287435.aspx
}
if (task.Status == TaskStatus.RanToCompletion)
{
onEvent(task.Result);
return true;
}
return false;
}
Update 2: Another great solution
Turns out that BlockingCollection works just like ConcurrentQueue but also has methods accepting a timeout and cancellation token. One nice thing about this solution is that it can be updated to make a WaitForNEvents fairly easily:
public static bool WaitForSingleEvent<TEvent>(this CancellationToken token, Action<TEvent> handler, Action<Action<TEvent>> subscribe, Action<Action<TEvent>> unsubscribe, int msTimeout, Action initializer = null)
{
var q = new BlockingCollection<TEvent>();
Action<TEvent> add = item => q.TryAdd(item);
subscribe(add);
try
{
if (initializer != null)
{
initializer();
}
TEvent eventResult;
if (q.TryTake(out eventResult, msTimeout, token))
{
handler(eventResult);
return true;
}
return false;
}
finally
{
unsubscribe(add);
q.Dispose();
}
}
You can use TaskCompletetionSource to create a Task that you can mark as completed or cancelled. Here's a possible implementation for a specific event:
public Task WaitFirstMyEvent(Foo target, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<object>();
Action handler = null;
var registration = cancellationToken.Register(() =>
{
target.MyEvent -= handler;
tcs.TrySetCanceled();
});
handler = () =>
{
target.MyEvent -= handler;
registration.Dispose();
tcs.TrySetResult(null);
};
target.MyEvent += handler;
return tcs.Task;
}
In C# 5 you can use it like this:
private async Task MyMethod()
{
...
await WaitFirstMyEvent(foo, cancellationToken);
...
}
If you want to wait for the event synchronously, you can also use the Wait method:
private void MyMethod()
{
...
WaitFirstMyEvent(foo, cancellationToken).Wait();
...
}
Here's a more generic version, but it still works only for events with Action signature:
public Task WaitFirstEvent(
Action<Action> subscribe,
Action<Action> unsubscribe,
CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<object>();
Action handler = null;
var registration = cancellationToken.Register(() =>
{
unsubscribe(handler);
tcs.TrySetCanceled();
});
handler = () =>
{
unsubscribe(handler);
registration.Dispose();
tcs.TrySetResult(null);
};
subscribe(handler);
return tcs.Task;
}
You can use it like this:
await WaitFirstEvent(
handler => foo.MyEvent += handler,
handler => foo.MyEvent -= handler,
cancellationToken);
If you want it to work with other event signatures (e.g. EventHandler), you will have to create separate overloads. I don't think there's an easy way to make it work for any signature, especially since the number of parameters isn't always the same.
You can use Rx to convert the event to an observable, then to a task, and finally wait on that task with your token/timeout.
One advantage this has over any of the existing solutions, is that it calls unsubscribe on the event's thread, ensuring that your handler won't be called twice. (In your first solution you work around this by tcs.TrySetResult instead of tcs.SetResult, but it's always nice to get rid of a "TryDoSomething" and simply ensure DoSomething always works).
Another advantage is the code's simplicity. It's essentially one line. So you don't even particularly need an independent function. You can inline it so that it's more clear what exactly your code does, and you can make variations on the theme without needing a ton of optional parameters (like your optional initializer, or allow waiting on N events, or foregoing timeouts/cancellation in instances where they're not necessary). And you'd have both the bool return val and the actual result in scope when it's finished, if that's useful at all.
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
...
public static bool WaitForSingleEvent<TEvent>(this CancellationToken token, Action<TEvent> onEvent, Action<Action<TEvent>> subscribe, Action<Action<TEvent>> unsubscribe, int msTimeout, Action initializer = null) {
var task = Observable.FromEvent(subscribe, unsubscribe).FirstAsync().ToTask();
if (initializer != null) {
initializer();
}
try {
var finished = task.Wait(msTimeout, token);
if (finished) onEvent(task.Result);
return finished;
} catch (OperationCanceledException) { return false; }
}
many thanks!
for helping other to understand...
(maybe showing serialdevice code with hits action handler code)
you could also put a generic type constrain adding something like
where TEvent : EventArgs
in my case i also need the result out of event in the "waiter"
so i changed signature like
(fast and ugly on a generic object...)
public static bool WaitForSingleEventWithResult<TEvent, TObjRes>(
this CancellationToken token,
Func<TEvent, TObjRes> onEvent,
...
calling it in this way
var ct = new CancellationToken();
object result;
bool eventOccurred = ct.WaitForSingleEventWithResult<MyEventArgs, object>(
onEvent: statusPacket => result = this.OnStatusPacketReceived(statusPacket),
subscribe: sub => cp.StatusPacketReceived_Action += sub,
unsubscribe: unsub => cp.StatusPacketReceived_Action -= unsub,
msTimeout: 5 * 1000,
initializer: /*() => serialDevice.RequestStatusPacket()*/null);
anyway... many thanks!
Why not just use
ManualResetEventSlim.Wait (int millisecondsTimeout, CancellationToken cancellationToken)
?

Is that make sense atomic for MoveNext in async generated StateMachine

Recently, I am reading Eduasync serial in Jon Skeet’s blog. When I read in part 7, one question blocked me, I thought the C# generated statemachine may not work properly in some rare case, let’s deep in code(this code is from Jon Skeet's Eduasync part 7, I just add some commends):
public void MoveNext()
{
int result;
try
{ // doFinallyBodies is never used
bool doFinallyBodies = true;
if (state != 1)
{
if (state != -1)
{
task = Task<int>.Factory.StartNew(() => 5);
awaiter = task.GetAwaiter();
// In a rare case, in this moment the task still has not completed,
// so return false IsCompleted
if (awaiter.IsCompleted)
{
goto Label_GetResult;
}
state = 1;
// The task just completed before OnCompleted,
// but in this moment we haven't call the OnCompleted yet,
// so the task's ContinueWith is nothing the task will complete
// without ContinueWith and we will never get back to this StateMachine again.
doFinallyBodies = false;
awaiter.OnCompleted(moveNextDelegate);
}
return;
}
state = 0;
Label_GetResult:
int awaitResult = awaiter.GetResult();
awaiter = new TaskAwaiter<int>();
result = awaitResult;
}
catch (Exception e)
{
state = -1;
builder.SetException(e);
return;
}
state = -1;
builder.SetResult(result);
}
public struct TaskAwaiter<T>
{
private readonly Task<T> task;
internal TaskAwaiter(Task<T> task)
{
this.task = task;
}
public bool IsCompleted { get { return task.IsCompleted; } }
public void OnCompleted(Action action)
{
SynchronizationContext context = SynchronizationContext.Current;
TaskScheduler scheduler = context == null ? TaskScheduler.Current
: TaskScheduler.FromCurrentSynchronizationContext();
task.ContinueWith(ignored => action(), scheduler);
}
public T GetResult()
{
return task.Result;
}
}
So do you think this could be a problem?
To make sure I understand you correctly, I'll describe the sequence of events I think you're expecting in more detail:
The asynchronous operation is started
IsCompleted is checked, which will return false, because the operation didn't finish yet
The operation completes
OnCompleted() is called, which in turn calls ContinueWith(), but because the Task has already completed, the continuation is never executed
If I got this correct, then your mistake is in step 4. That's because the authors of Task were aware of this race condition, and so if you call ContinueWith() on an already completed Task, the continuation will be scheduled immediatelly. Because of that, the state machine will work correctly even in this situation.
Unfortunately, the documentation for ContinueWith() isn't very clear about this (it explains when the continuation won't be scheduled, but not when it will).

Categories

Resources