CancellationTokenSource cancelling more then expected - c#

Basically i am running a programm that executes a method that is repeated several times (for example 7 times), but i need an option to cancel the CURRENTLY run one of it, but still allow new ones to start.
My issue is that the programm ends as soon as i hit the cancel button. So i seem to be missing something.
Main:
for(int i = 0; i < 7; i++)
{
cts = new CancellationTokenSource();
taskUbung = Task.Factory.StartNew(async() =>
{
await doSomething();
}, cts.Token);
}
Button:
private void buttonSkipUbung_Click(object sender, RoutedEventArgs e)
{
cts.Cancel();
}
So if i am hitting the button on the 3rd round of doSomething(), the remaining 4 will never execute.
What do i have to change for my desired behavior? I could just use some booleans and return in doSomething(), but i figured this would be cleaner and more responsive, if it works that is.

You need to keep track of the tokens you are creating in some kind of list. Otherwise you only remember the last one and call cancel only on that one

Related

Delay function in C#

I need to understand how can I create delays between a set of commands. My background is with C (DOS) and now reviving the concepts using C# in Visual Studio 2015. This is the code I am struggling with:
using System.Threading;
private void button1_Click(object sender, EventArgs e) // Button
{
int i;
for (i = 0; i < 10; i++)
{
textBox1.BackColor = Color.Red;
Thread.Sleep(100);
textBox1.BackColor = Color.Yellow;
Thread.Sleep(100);
}
}
I was expecting the background color of the textbox will change alternatively 10 times but I could see only yellow color after the loop finishes. If I increase delay I do notice that program takes time to finish. I went through some related articles but couldn't get the point. Any help will be appreciated. Thanks
Use an async method to create a delay using the built-in Task.Delay method. This will cause execution to be paused and then resumed after the specified time without blocking the current thread.
async Task UseDelay()
{
await Task.Delay(1000); // wait for 1 second
}
In your specific case
async void button1_Click(object sender, EventArgs e)
{
for (var i = 0; i < 10; i++)
{
textBox1.BackColor = Color.Red;
await Task.Delay(100);
textBox1.BackColor = Color.Yellow;
await Task.Delay(100);
}
}
The problem isn't with the delaying, it's with the threading model of UI applications. In a UI application, any event handlers happen on the "UI thread". While that code is running, the UI is essentially frozen, so nothing you do there matters.
That means if you "Sleep" in there, the entire application will lock up and be unresponsive until it returns.
But you can make your event handlers "async void" instead of just "void" if they need to do long running work. Then if you await Task.Delay(someTime) instead of Thread.Sleep(someTime), it will release the UI thread while that's happening. And you should see what you expect without the UI locking up.
Also, that time is in milliseconds, meaning wait "one tenth of a second". Which is really, really fast. You might want to slow it down a bit to get the effect you want.

Right way to continuously update the UI

Assuming that a client app gets data from a server nearly in real time. What is the more efficient way to continuously update the UI based on the retrieved data. Think of multiple xaml controls, like texts that show numbers. Those get updated as long as the application is running. They never stop unless the user decides it. (let's say by pressing a stop button or exit the app)
Below I have a simple example utilizing async and await keywords. Is that a good way for my scenario? Or for example BackgroundWorker would be a better way?
private async void Button_Click_Begin_RT_Update(object sender, RoutedEventArgs e)
{
while(true)
textField1.Text = await DoWork();
}
Task<string> DoWork()
{
return Task.Run(() =>
{
return GetRandomNumberAsString();
});
}
*for the sake of simplicity I use code-behind and not mvvm in my example
Your code is more or less OK if your GetRandomNumberAsString() takes at least 15ms to complete.
If it takes less than that, and you want to minimize update latency i.e. you don't want to just wait, you might want to (1) replace your per-operation Task.Run with an endless loop that completely runs in a background thread (2) Implement throttling mechanism in that loop, and only update your GUI (using e.g. Dispatcher.BeginInvoke()) at around 30-60Hz.
P.S. The exact mechanism how you update your GUI (databinding + INotifyPropertyChanged, or directly like in your code) is not relevant for performance.
Update: here's example (untested)
static readonly TimeSpan updateFrequency = TimeSpan.FromMilliseconds( 20 );
void ThreadProc()
{
Stopwatch sw = Stopwatch.StartNew();
while( true )
{
string val = GetRandomNumberAsString();
if( sw.Elapsed < updateFrequency )
continue; // Too early to update
sw.Restart();
Application.Current.Dispatcher.BeginInvoke( () => { textField1.Text = val; } );
}
}

cancelling a backgroundworker with while loop

i know the common ways of cancelling a backgroundworker using eventwaithandles...
but i wanna know is that right to use a while loop to trap and pause working of a backgroundworker ? i coded like this :
Bool stop = false;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100000;
progressBar1.Value = 0;
for (int i = 0; i < 100000; i++)
{
progressBar1.Value++;
if (i == 50000)
stop = true;
while (stop)
{ }
}
}
private void button1_Click(object sender, EventArgs e)
{
stop = !stop;
}
Did you try it? What happened? Was it what you wanted to happen? Did you notice your computer's fans speeding up, to handle all the heat from your CPU in a tight, "do-nothing" loop?
Fact is, you should not "pause" a background task in the first place; if you don't it to keep running, interrupt it. If you want to be able to resume later, provide a mechanism to allow that. Even having your thread blocked efficiently waiting on a WaitHandle object would be the wrong thing to do, because it wastes a thread pool thread.
The code you've posted here is about the worst way to implement "pausing". Instead of waiting on some synchronization object such as a WaitHandle, you have the current thread just loop without interrupting, constantly checking the value of a flag. Even ignoring the question of whether you're using volatile (the code example doesn't show that, but then it also wouldn't compile, so…), it's terrible to force a CPU core to do so much work and yet get nowhere.
Don't pause your BackgroundWorker.DoWork handler in the first place. Really. Just don't do that. But if you insist, then at least use some kind of waitable object instead of a "spin-wait" loop as in the example you've posted here.
Here's an example of how your code might work if you wanted to avoid altogether tying up a thread while "paused". First, don't use BackgroundWorker, because it doesn't have a graceful way to do this. Second, do use await…that does specifically what you want: it allows the current method to return, but without losing track of its progress. The method will resume executing when the thing it waited on indicates completion.
In the example below, I've tried to guess at what the code that calls RunWorkerAsync() looks like. Or rather, I just assumed you've got a button2, which when clicked you call that method to start your worker task. If this is not enough to get you pointed in the right direction, please improve your question by including a good, minimal, complete code example showing what you're actually doing.
// These fields will work together to provide a way for the thread to interrupt
// itself temporarily without actually using a thread at all.
private TaskCompletionSource<object> _pause;
private readonly object _pauseLock = new object();
private void button2_Click(object sender, DoWorkEventArgs e)
{
// Initialize ProgressBar. Note: in your version of the code, this was
// done in the DoWork event handler, but that handler isn't executed in
// the UI thread, and so accessing a UI object like progressBar1 is not
// a good idea. If you got away with it, you were lucky.
progressBar1.Minimum = 0;
progressBar1.Maximum = 100000;
progressBar1.Value = 0;
// This object will perform the duty of the BackgroundWorker's
// ProgressChanged event and ReportProgress() method.
Progress<int> progress = new Progress<int>(i => progressBar1.Value++);
// We do want the code to run in the background. Use Task.Run() to accomplish that
Task.Run(async () =>
{
for (int i = 0; i < 100000; i++)
{
progress.Report(i);
Task task = null;
// Locking ensures that the two threads which may be interacting
// with the _pause object do not interfere with each other.
lock (_pauseLock)
{
if (i == 50000)
{
// We want to pause. But it's possible we lost the race with
// the user, who also just pressed the pause button. So
// only allocate a new TCS if there isn't already one
if (_pause == null)
{
_pause = new TaskCompletionSource<object>();
}
}
// If by the time we get here, there's a TCS to wait on, then
// set our local variable for the Task to wait on. In this way
// we resolve any other race that might occur between the time
// we checked the _pause object and then later tried to wait on it
if (_pause != null)
{
task = _pause.Task;
}
}
if (task != null)
{
// This is the most important part: using "await" tells the method to
// return, but in a way that will allow execution to resume later.
// That is, when the TCS's Task transitions to the completed state,
// this method will resume executing, using any available thread
// in the thread pool.
await task;
// Once we resume execution here, reset the TCS, to allow the pause
// to go back to pausing again.
lock (_pauseLock)
{
_pause.Dispose();
_pause = null;
}
}
}
});
}
private void button1_Click(object sender, EventArgs e)
{
lock (_pauseLock)
{
// A bit more complicated than toggling a flag, granted. But it achieves
// the desirable goal.
if (_pause == null)
{
// Creates the object to wait on. The worker thread will look for
// this and wait if it exists.
_pause = new TaskCompletionSource<object>();
}
else if (!_pause.Task.IsCompleted)
{
// Giving the TCS a result causes its corresponding Task to transition
// to the completed state, releasing any code that might be waiting
// on it.
_pause.SetResult(null);
}
}
}
Note that the above is just as contrived as your original example. If all you had really was a simple single loop variable iterating from 0 to 100,000 and stopping halfway through, nothing nearly so complicated as the above would be required. You'd just store the loop variable in a data structure somewhere, exit the running task thread, and then when you want to resume, pass in the current loop variable value so the method can resume at the right index.
But I'm assuming your real-world example is not so simple. And the above strategy will work for any stateful processing, with the compiler doing all the heavy-lifting of storing away intermediate state for you.

C# BackgroundWorker

I have a button that on click event I get some information from the network.
When I get information I parse it and add items to ListBox. All is fine, but when I do a fast double-click on button, it seems that two background workers are running and after finishing all work, items in the list are dublicated.
I want to do so that if you click button and the proccess of getting information is in work, this thread is stopping and only after first work is completed the second one is beginning.
Yes, I know about AutoResetEvent, but when I used it it helped me only one time and never more. I can't implement this situation and hope that you will help me!
Now I even try to make easier but no success :( : I added a flag field(RefreshDialogs)(default false), when the user clicks on button, if flag is true(it means that work is doing), nothing is doing, but when flag field is set to false, all is fine and we start a new proccess.
When Backgroundwork completes, I change field flag to false(it means that user can run a new proccess).
private void Message_Refresh_Click(object sender, EventArgs e)
{
if (!RefreshDialogs)
{
RefreshDialogs = true;
if (threadBackgroundDialogs.WorkerSupportsCancellation)
{
threadBackgroundDialogs.CancelAsync();
}
if (!threadBackgroundDialogs.IsBusy)
{
downloadedDialogs = 0;
threadBackgroundDialogs = new BackgroundWorker();
threadBackgroundDialogs.WorkerSupportsCancellation = true;
threadBackgroundDialogs.DoWork += LoadDialogs;
threadBackgroundDialogs.RunWorkerCompleted += ProcessCompleted;
threadBackgroundDialogs.RunWorkerAsync();
}
}
}
void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RefreshDialogs = false;
}
So you want to keep the second process running while the first works, but they shouldn't disturb each other? And after the first one finishes the second one continues?
Crude way: While loop:
if (!RefreshDialogs)
{
RefreshDialogs = true;
this becomes:
while(RefreshDialogs)
{
}
RefreshDialogs = true;
After you set it false the second process wwill jump out of the while. (Note this is extremly inefficent since both processes will be running all the time, i'm pretty sure the second one will block the first one, but with multitasking now it shouldn't, if it block use a Dispatcher.Thread)
Elegant way: Use A Semaphore
http://msdn.microsoft.com/de-de/library/system.threading.semaphore%28v=vs.80%29.aspx
If you find it impossible to have both processes running at the same time, or want another way:
Add an Array/List/int and when the second process notices there is the first process running, like with your bool, increase your Added variable, and at the end of the process, restart the new process and decrese the variable:
int number;
if (!RefreshDialogs)
{
RefreshDialogs = true;
your code;
if(number > 0)
{
number--;
restart process
}
}
else
{
number++;
}
I have to admit, i like my last proposal the most, since its highly efficent.
Make your thread blocking. That is easy;
lock(someSharedGlobalObject)
{
Do Work, Exit early if cancelled
}
This way other threads will wait until the first thread releases the lock. They will never execute simultaneously and silently wait until they can continue.
As for other options; why not disable the button when clicked and re-enable it when the backgroundworker completes. Only problem is this does not allow for cancelling the current thread. The user has to wait for it to finish. It does make any concurrency go away very easily.
How about this approach?
Create a request queue or counter which will be incremented on every button click. Every time that count is > 0. Start the background worker. When the information comes, decrement the count and check for 0. If its still > 0 restart the worker. In that your request handler becomes sequential.
In this approach you may face the problem of continuous reference of the count by two threads, for that you may use a lock unlock condition.
I hav followed this approach for my app and it works well, hope it does the same for you.
I'm not an Windows Phone expert, but as I see it has support for TPL, so following code would read nicely:
private object syncRoot =new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
latestTask = Task.Factory.StartNew(action);
else
latestTask = latestTask.ContinueWith(tsk => action());
}
}
Use can use semaphores
class TheClass
{
static SemaphoreSlim _sem = new SemaphoreSlim (3);
static void Main()
{
for (int i = 1; i <= 5; i++)
new Thread (Enter).Start (i);
}
static void Enter (object name)
{
Console.WriteLine (name + " wants to enter");
_sem.Wait();
Console.WriteLine (name + " has entered!");
Thread.Sleep (1000 * (int) name );
Console.WriteLine (name + " is leaving");
_sem.Release(); }
}
}
I found the solution and thanks to #Giedrius. Flag RefreshingDialogs is set to true only when proccess is at the end, when I added items to Listbox. The reason why I'am using this flag is that state of process changes to complete when the asynchronous operation of getting content from network(HttpWebRequest, method BeginGetRequestStream) begins, but after network operaion is complete I need to make UI operations and not only them(parse content and add it to Listbox)My solution is:
private object syncRoot = new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
{
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
else if(latestTask.IsCompleted && !RefreshingDialogs)
{
RefreshingDialogs = true;
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
}
}
private void Message_Refresh_Click(object sender, EventArgs e)
{
Action ac = new Action(LoadDialogs2);
EnqueueAction(ac);
}

Automatically call a task every 5 seconds

i have an Infragistics carousel control which i want to call "next" on every 5 seconds. However im not sure how to do this without a while true.
Any help would be great, thanks!
Currently its kicked off from a click, starting a task within a while true. Obviously this i what i want to avoid.
private void GoToNext(object sender, MouseButtonEventArgs e)
{
while (true)
{
Task task = new Task(() => MyCarousel.Dispatcher.BeginInvoke(new next(goToNext), null));
task.Start();
}
}
private bool goToNext()
{
Thread.Sleep(15);
MyCarousel.ExecuteCommand(Infragistics.Windows.Controls.XamCarouselPanelCommands.NavigateToNextItem);
return true;
}
Timers are used for this in general, sitting in the background and triggering every so often. There are a number in .NET (in System.Timers and elsewhere) and which one is best depends on your particular scenario.

Categories