Cancel Operations / UI Notification and UI Information? - c#

I'm currently working on a small project that use Tasks.Dataflow and I'm a little bit confused about UI notifications. I want to separate my "Pipeline" from the UI in another class called PipelineService, but I'm unable to notify the UI on cancelled operations or data that should be shown up in the UI. How can this be handled in the right manner?
Code:
private void btnStartPipeline_Click(object sender, EventArgs e)
{
btnStartPipeline.Enabled = false;
btnStopPipeline.Enabled = true;
cancellationToken = new CancellationTokenSource();
if (head == null)
{
head = pipeline.SearchPipeline();
}
head.Post(AppDirectoryNames.STORE_PATH);
}
private void btnStopPipeline_Click(object sender, EventArgs e)
{
cancellationToken.Cancel();
}
This methods related to Form1.cs. head is type of ITargetBlock<string>.
public ITargetBlock<string> SearchPipeline()
{
var search = new TransformBlock<string, IEnumerable<FileInfo>>(path =>
{
try
{
return Search(path);
}
catch (OperationCanceledException)
{
return Enumerable.Empty<FileInfo>();
}
});
var move = new ActionBlock<IEnumerable<FileInfo>>(files =>
{
try
{
Move(files);
}
catch (OperationCanceledException ex)
{
throw ex;
}
});
var operationCancelled = new ActionBlock<object>(delegate
{
form.Invoke(form._update);
},
new ExecutionDataflowBlockOptions
{
TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
});
search.LinkTo(move);
search.LinkTo(operationCancelled);
return search;
}
Invoke don't take effect with delegate methods. What am I doing wrong here?

At first, I din't understand why you think your code should work. The way you set up your dataflow network, each IEnumerable<FileInfo> generated by the search block is first sent to the move block. If the move block didn't accept it (which never happens here), it would be sent to the operationCancelled block. That doesn't seem to be what you want at all.
After looking at the walkthough you seem to be basing your code on, it does cancellation similar than you, but with one significant difference: it uses LinkTo() with a predicate, which rejects a message that signifies cancellation. If you wanted to do the same, you would need to also use LinkTo() with a predicate. And since I don't think an empty sequence is a good choice to signify cancellation, I think you should switch to null too.
Also, you don't need to use form.Invoke() if you're already using TaskScheduler.FromCurrentSynchronizationContext(), they do basically the same thing.
public ITargetBlock<string> SearchPipeline()
{
var search = new TransformBlock<string, IEnumerable<FileInfo>>(path =>
{
try
{
return Search(path);
}
catch (OperationCanceledException)
{
return null;
}
});
var move = new ActionBlock<IEnumerable<FileInfo>>(files =>
{
try
{
Move(files);
}
catch (OperationCanceledException)
{
// swallow the exception; we don't want to fault the block
}
});
var operationCancelled = new ActionBlock<object>(_ => form._update(),
new ExecutionDataflowBlockOptions
{
TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
});
search.LinkTo(move, files => files != null);
search.LinkTo(operationCancelled);
return search;
}

Related

Dynamically search with interrupts,via Tasks C#

I'm working with Db(via SQLite.NET PCL,not async version). At current moment i have a listview with some data(taken from db),also i got a searchbar/entry(its nvm),where user can input some values and then,via LINQ i'm going to make a query and update SourceItems of my List.
So the problems comes with performance,because my DB got million records and simple LINQ query working very slow.In other words,when user enter too fast some data,application gets huge lags and sometimes can Crash.
To resolve this problem,some things come in my mind(theoretically solution):
1)Need to put method(which i make query into db) on Task(to unlock my main UI thread)
2)Initialize timer,then turn on and :
if 1 second passed,then => run my method(query) on Task(similiar to background thread)
if 1 second doesn't passed,then exit from anonymous method.
Something like that(similar) or any suggestions.Thanks!
UPD:
So to be honest,i tried too much and didnt get a good result
BTW,my current code(Snippets) :
1) My SearchMethod
public void QueryToDB(string filter)
{
this.BeginRefresh ();
if (string.IsNullOrWhiteSpace (filter))
{
this.ItemsSource = SourceData.Select(x => x.name); // Source data is my default List of items
}
else
{
var t = App.DB_Instance.FilterWords<Words>(filter); //FilterWords it's a method,where i make direct requests to the database
this.ItemsSource = t.Select(x => x.name);
}
this.EndRefresh ();
}
2)Searchbar.TextChanged (anonymous method)
searchBar.TextChanged +=async (sender, e) =>
{
ViewModel.isBusy = true; //also i got a indicator,to show progress,while query working
await Task.Run(()=> //my background,works fine
{
listview.QueryToDB(searchBar.Text);
});
ViewModel.isBusy = false; // after method is finished,indicator turn off
};
The main problem is how to implement this part(with these case's),where 1 second passed and only then i'm going to make query to update my sourceItems of list(everytime,when user inputs some value into searchbar,this trigger(timer) must refresh again to zero).
Any help will be appreciated,thanks!
PS Sorry for my eng. skills!
One way to do it is to combine async Task.Run and CancellationTokenSource:
CancellationTokenSource cancellationTokenSource;
searchView.TextChanged += async (sender, e) =>
{
if (cancellationTokenSource != null) cancellationTokenSource.Cancel();
cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;
var searchBar = (sender as SearchBar);
if (searchBar != null)
{
string searchText = searchBar.Text;
try
{
await Task.Delay(650, cancellationToken);
if (cancellationToken.IsCancellationRequested) return;
var searchResults = await Task.Run(() =>
{
return ViewModel.Search(searchText);
});
if (cancellationToken.IsCancellationRequested) return;
ViewModel.YouItems.Repopulate(searchResults);
}
catch (OperationCanceledException)
{
// Expected
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
};
You want to wait before actually performing your search. Killing a search task in midway can cause undefined behavior.
You want to save the current search filter and compared it again 1 second later. If that hasn't changed, do the search. Otherwise, abort :
searchBar.TextChanged += async (sender, e) =>
{
var filter = searchBar.Text;
await Task.Run(() =>
{
Thread.Sleep(1000);
if (filter == searchBar.Text)
listview.QueryToDB(searchBar.Text);
});
};
As to keep the view model updated, move your isBusy assignments inside QueryToDB because that is when your view model is truly busy :
public void QueryToDB(string filter)
{
this.BeginRefresh ();
ViewModel.isBusy = true;
// do your search
ViewModel.isBusy = false;
this.EndRefresh ();
}

Deadlock when calling Dispatcher.Invoke() twice

I have two dispatcher:
dispatcher1
dispatcher2
Now, when I call (this is a simplified sample of my complex code):
var ret = dispatcher1.Invoke(() => {
return dispatcher2.Invoke(() => {
return new object();
});
});
I will run in a deadlock.
the call of
dispatcher1.Invoke()
is now waiting in
DispatcherSynchronizationContext.Wait()
and also the dispatcher2 after calling
dispatcher2.Invoke()
is waiting in
DispatcherSynchronizationContext.Wait
I cannot change the Invoke-Calls to async calls (BeginInvoke) because I need the result.
This was not the case with .NET 4.0 - only since I have changed to .NET 4.5.
Is there a way to solve this?
This is a really, really terrible solution, and you should not use it. Ever.
But if you feel like living dangerously, try replacing your Invoke calls with the InvokeAndPump extension method below. (Don't replace every call to Invoke in your project--just the problematic ones in the question.)
public static class DispatcherExtensions
{
public static T InvokeAndPump<T>(
this Dispatcher dispatcher,
Func<T> function,
DispatcherPriority priority = DispatcherPriority.Normal)
{
if (dispatcher == null)
throw new ArgumentNullException("dispatcher");
if (function == null)
throw new ArgumentNullException("function");
// If you've found this code in your project, you are doomed. <3
Action wait, notify;
var currentDispatcher = Dispatcher.FromThread(Thread.CurrentThread);
if (currentDispatcher != null)
{
var frame = new DispatcherFrame();
wait = () => Dispatcher.PushFrame(frame);
notify = () => frame.Continue = false;
}
else
{
var waitEvent = new ManualResetEventSlim(false);
wait = waitEvent.Wait;
notify = waitEvent.Set;
}
var error = default(Exception);
var result = default(T);
dispatcher.BeginInvoke(
priority,
new Action(
() =>
{
try { result = function(); }
catch (Exception e) { error = e; }
finally { notify(); }
}));
// Hold on to your butts...
wait();
if (error != null)
throw new TargetInvocationException(error);
return result;
}
}
Seriously, though: heaven help anyone who uses this and expects it to work reliably. I'm only posting it out of curiosity and because I am evil. Mostly the evil.

Good pattern for exception handling when using async calls

I want to consume an Web API and I see many people recommending System.Net.Http.HttpClient.
That's fine... but I have only VS-2010, so I cannot use async/await just yet. Instead, I guess I could use Task<TResult> in combination to ContinueWith. So I tried this piece of code:
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.GetStringAsync(STR_URL_SERVER_API_USERS).ContinueWith(task =>
{
var usersResultString = task.Result;
lbUsers.DataSource = JsonConvert.DeserializeObject<List<string>>(usersResultString);
});
My first observation was to realize that it doesn't generate any error if URL is not available, but maybe there will be more errors like this...
So I am trying to find a way to handle exceptions for such async calls (particularly for HttpClient). I noticed that "Task" has IsFaulted property and an AggregateException which maybe could be used, but I am not sure yet how.
Another observation was that GetStringAsync returns Task<string>, but GetAsync returns Task<HttpResponseMessage>. The latter could be maybe more useful, since it presents a StatusCode.
Could you share a pattern on how to use the async calls correctly and handle exceptions in a good way? Basic explanation would be appreciated as well.
I would not use a separate ContinueWith continuation for successful and faulted scenarios. I'd rather handle both cases in a single place, using try/catch:
task.ContinueWith(t =>
{
try
{
// this would re-throw an exception from task, if any
var result = t.Result;
// process result
lbUsers.DataSource = JsonConvert.DeserializeObject<List<string>>(result);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
lbUsers.Clear();
lbUsers.Items.Add("Error loading users!");
}
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext()
);
If t is a non-generic Task (rather than a Task<TResult>), you can do t.GetAwaiter().GetResult() to re-throw the original exception inside the ContinueWith lambda; t.Wait() would work too. Be prepared to handle AggregatedException, you can get to the inner exception with something like this:
catch (Exception ex)
{
while (ex is AggregatedException && ex.InnerException != null)
ex = ex.InnerException;
MessageBox.Show(ex.Message);
}
If you're dealing with a series of ContinueWith, usually you don't have to handle exceptions inside each ContinueWith. Do it once for the outermost resulting task, e.g.:
void GetThreePagesV1()
{
var httpClient = new HttpClient();
var finalTask = httpClient.GetStringAsync("http://example.com")
.ContinueWith((task1) =>
{
var page1 = task1.Result;
return httpClient.GetStringAsync("http://example.net")
.ContinueWith((task2) =>
{
var page2 = task2.Result;
return httpClient.GetStringAsync("http://example.org")
.ContinueWith((task3) =>
{
var page3 = task3.Result;
return page1 + page2 + page3;
}, TaskContinuationOptions.ExecuteSynchronously);
}, TaskContinuationOptions.ExecuteSynchronously).Unwrap();
}, TaskContinuationOptions.ExecuteSynchronously).Unwrap()
.ContinueWith((resultTask) =>
{
httpClient.Dispose();
string result = resultTask.Result;
try
{
MessageBox.Show(result);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
Any exceptions thrown inside inner tasks will propagate to the outermost ContinueWith lambda as you're accessing the results of the inner tasks (taskN.Result).
This code is functional, but it's also ugly and non-readable. JavaScript developers call it The Callback Pyramid of Doom. They have Promises to deal with it. C# developers have async/await, which you're unfortunately not able to use because of the VS2010 restrain.
IMO, the closest thing to the JavaScript Promises in TPL is Stephen Toub's Then pattern. And the closest thing to async/await in C# 4.0 is his Iterate pattern from the same blog post, which uses the C# yield feature.
Using the Iterate pattern, the above code could be rewritten in a more readable way. Note that inside GetThreePagesHelper you can use all the familiar synchronous code statements like using, for, while, try/catch etc. It is however important to understand the asynchronous code flow of this pattern:
void GetThreePagesV2()
{
Iterate(GetThreePagesHelper()).ContinueWith((iteratorTask) =>
{
try
{
var lastTask = (Task<string>)iteratorTask.Result;
var result = lastTask.Result;
MessageBox.Show(result);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
IEnumerable<Task> GetThreePagesHelper()
{
// now you can use "foreach", "using" etc
using (var httpClient = new HttpClient())
{
var task1 = httpClient.GetStringAsync("http://example.com");
yield return task1;
var page1 = task1.Result;
var task2 = httpClient.GetStringAsync("http://example.net");
yield return task2;
var page2 = task2.Result;
var task3 = httpClient.GetStringAsync("http://example.org");
yield return task3;
var page3 = task3.Result;
yield return Task.Delay(1000);
var resultTcs = new TaskCompletionSource<string>();
resultTcs.SetResult(page1 + page1 + page3);
yield return resultTcs.Task;
}
}
/// <summary>
/// A slightly modified version of Iterate from
/// http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx
/// </summary>
public static Task<Task> Iterate(IEnumerable<Task> asyncIterator)
{
if (asyncIterator == null)
throw new ArgumentNullException("asyncIterator");
var enumerator = asyncIterator.GetEnumerator();
if (enumerator == null)
throw new InvalidOperationException("asyncIterator.GetEnumerator");
var tcs = new TaskCompletionSource<Task>();
Action<Task> nextStep = null;
nextStep = (previousTask) =>
{
if (previousTask != null && previousTask.Exception != null)
tcs.SetException(previousTask.Exception);
if (enumerator.MoveNext())
{
enumerator.Current.ContinueWith(nextStep,
TaskContinuationOptions.ExecuteSynchronously);
}
else
{
tcs.SetResult(previousTask);
}
};
nextStep(null);
return tcs.Task;
}

Task crash while trying to search folder without permission

This is my function that get IEnumerable<string> source and search all the files inside this path:
public void search()
{
Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach(_source,
new ParallelOptions
{
MaxDegreeOfParallelism = 5 //limit number of parallel threads here
},
file =>
{
FileChecker fileChecker = new FileChecker();
string result = fileChecker.check(file);
if (result != null)
OnFileAddEvent(result);
});
}
catch (Exception)
{ }
}).ContinueWith
(t =>
{
OnFinishSearchEvent();
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}
public void search2()
{
Task.Factory.StartNew(() =>
{
var filtered = _source.AsParallel()
.WithDegreeOfParallelism(5)
.Where(file =>
{
try
{
FileChecker fileChecker = new FileChecker();
string result = fileChecker.check(file);
if (result != null)
OnFileAddEvent(result);
return true;
}
catch (Exception)
{
return false;
}
});
return filtered.ToList();
}).ContinueWith
(t =>
{
OnFinishSearchEvent();
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}
It looks like you have a fundamental misunderstanding of Multithreading and Exception Handling.
Exception handling in .net typically starts with a managed exception being thrown. This then causes the .net VM to then walk up the call stack until it finds an appropriate try catch block.
In this case the Task.Factory.StartNew(Action), is a wrapper to push onto the thread pool work described in the Action delegate. The top of the call stack would in this case be the Action delegate described in...
file =>
{
// check my file before adding to my Listbox
}
So when an exception bubbles up...nothing is "up" the call stack to catch it.
The solution then is either to, as others have described, add a root level try catch in the delegate you pass into the Task.Factory.StartNew(Action) method.
More generally one would normally add a OnError continuation on the Task returned by the Task.Factory.StartNew(Action)...however I would also add that I would be worried that this entire method is highly flawed, as none of the worker threads should be able to add to the ListBox. The ListBox should ONLY ever be accessed by the STA thread that constructed it.
Ultimately I would change the entire method to the following...
public void search()
{
Task.Factory.StartNew(() =>
{
var filtered = source.AsParallel()
.WithDegreeOfParallelism(5)
.Where(file =>
{
try
{
//Some filter function...
}
catch(Exception)
{
return false;
}
});
return filtered.ToList();
}).ContinueWith
(t =>
{
foreach(var result in t.Result)
{
MyListBox.Add(result);
}
OnFinishSearchEvent();
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}
You must catch what is inside of the Task:
public void search()
{
try
{
Task.Factory.StartNew(() =>
{
try{
Parallel.ForEach(source,
new ParallelOptions
{
MaxDegreeOfParallelism = 5 //limit number of parallel threads here
},
file =>
{
// check my file before adding to my Listbox
});
}).ContinueWith
(t =>
{
OnFinishSearchEvent();
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
catch(Exception ex){
}
}
catch (Exception ex)
{
}
}

Set timeout to an operation

I have object obj which is 3rd party component,
// this could take more than 30 seconds
int result = obj.PerformInitTransaction();
I don't know what is happening inside.
What I know is if it take longer time, it is failed.
how to setup a timeout mechanism to this operation, so that if it takes more than 30 seconds I just throw MoreThan30SecondsException ?
You could run the operation in a separate thread and then put a timeout on the thread join operation:
using System.Threading;
class Program {
static void DoSomething() {
try {
// your call here...
obj.PerformInitTransaction();
} catch (ThreadAbortException) {
// cleanup code, if needed...
}
}
public static void Main(params string[] args) {
Thread t = new Thread(DoSomething);
t.Start();
if (!t.Join(TimeSpan.FromSeconds(30))) {
t.Abort();
throw new Exception("More than 30 secs.");
}
}
}
More simply using Task.Wait(TimeSpan):
using System.Threading.Tasks;
var task = Task.Run(() => obj.PerformInitTransaction());
if (task.Wait(TimeSpan.FromSeconds(30)))
return task.Result;
else
throw new Exception("Timed out");
If you don't want to block the main thread you can use a System.Threading.Timer:
private Thread _thread;
void Main(string[] args)
{
_thread = new ThreadStart(ThreadEntry);
_thread.Start();
Timer timer = new Timer(Timeout,null,30000,Timeout.Infinite);
}
void ThreadEntry()
{
int result = obj.PerformInitTransaction();
}
void TimeOut(object state)
{
// Abort the thread - see the comments
_thread.Abort();
throw new ItTimedOutException();
}
Jon Skeet has a less forceful way (Shutting Down Worker Threads Gracefully) of stopping the thread than abort.
However as you're not in control of the operations PerformInitTransaction() is doing there is not much you can do from when Abort fails and leaves the object in an invalid state. As mentioned if you are able to cleanup anything that aborting the PerformInitTransaction has left hanging, you can do this by catching the ThreadAbortException, though as it's a 3rd party call it'll mean guessing the state you've left their method in.
The PerformInitTransaction should really be the one providing the timeout.
The following are two implementations which also throw any exception that happens in the internal task.
For actions (no return value):
public static bool DoWithTimeout(Action action, int timeout)
{
Exception ex = null;
CancellationTokenSource cts = new CancellationTokenSource();
Task task = Task.Run(() =>
{
try
{
using (cts.Token.Register(Thread.CurrentThread.Abort))
{
action();
}
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
ex = e;
}
}, cts.Token);
bool done = task.Wait(timeout);
if (ex != null)
throw ex;
if (!done)
cts.Cancel();
return done;
}
For Funcs (with return value):
public static bool DoWithTimeout<T>(Func<T> func, int timeout, out T result)
{
Exception ex = null;
result = default(T);
T res = default(T);
CancellationTokenSource cts = new CancellationTokenSource();
Task task = Task.Run(() =>
{
try
{
using (cts.Token.Register(Thread.CurrentThread.Abort))
{
res = func();
}
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
ex = e;
}
}, cts.Token);
bool done = task.Wait(timeout);
if (ex != null)
throw ex;
if (done)
result = res;
else
cts.Cancel();
return done;
}
I think this is simplest of all:
using System.Threading.Tasks;
var timeToWait = 30000; //ms
Task.Run(async () =>
{
await Task.Delay(timeToWait);
//do your timed task i.e. --
int result = obj.PerformInitTransaction();
});
You need to be careful about aborting an operation like this, especially as it's in a 3rd party component that you (possibly) don't have access to the code to modify.
If you abort the operation then you won't know what state you've left the underlying class in. For example, it may have acquired a lock, and your about has caused that lock to not be released. Even if you destroy the object after aborting the operation it may have altered some state that is global to it and therefore you won't be able to reliably create a new instance without a restart.
You might look at invoking the method in a thread and upon the timeout, abort the thread and raise the exception. Also, you shall have to handle the ThreadBorted Exception in this case.
New approach in .NET 6 / C# 10:
var task = Task.Run(() => SomeMethod(input));
return await task.WaitAsync(TimeSpan.FromSeconds(30));
There is a nice example of a generic solution to this using a helper class here.
It uses the Action delegate to avoid the Thread creation/destruction shown in the previous example.
I hope this helps.
this is what I would use. works similar to how a javascript timeout works.
public class Toolz {
public static System.Threading.Tasks.Task<object> SetTimeout(Func<object> func, int secs) {
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(secs));
return System.Threading.Tasks.Task.Run(() => func());
}
}
class Program {
static void Main(string[] args) {
Console.WriteLine(DateTime.Now);
Toolz.SetTimeout(() => {
Console.WriteLine(DateTime.Now);
return "";
}, 10);
}
}
I just ran into this in a .NET 4.0 app (no access to Task.Run, Task.Delay, etc.). If you will excuse the last line (which is the setTimeout part) it's fairly concise.
int sleepTime = 10000;
Action myAction = () => {
// my awesome cross-thread update code
this.BackColor = Color.Red;
};
new System.Threading.Thread(() => { System.Threading.Thread.Sleep(sleepTime); if (InvokeRequired) myAction(); else myAction(); }).Start();

Categories