Pausing background thread with AutoResetEvent.WaitOne() and .Set() - c#

I have following code. I'm trying to make buttons to main Form which can Pause, Continue and Stop the background thread the downloader is running on (private Thread thread)
Form1.cs
private AutoResetEvent waitHandle = new AutoResetEvent(true);
private Thread thread;
private void ThreadJob()
{
Downloader download = new Downloader();
download.runDownloader();
}
// THREADS button1 is "Download now"-button
private void button1_Click(object sender, EventArgs e)
{
ThreadStart job = new ThreadStart(ThreadJob);
thread = new Thread(job);
thread.IsBackground = true;
thread.Start();
}
This code is ran on Windows Form. I have buttons for all those actions (Pause, Continue, Stop)
Pause and continue button has code on form
private void btnPause_Click(object sender, EventArgs e)
{
waitHandle.WaitOne(); // Need to pause the background thread
}
private void btnContinue_Click(object sender, EventArgs e)
{
waitHandle.Set(); // Need to continue the background thread
}
The problem is pressing Pause button will freeze the main Form not the background thread.

It is runDownloader() that must be able to pause.
It will need to periodically call waitHandle.WaitOne() on the wait handle.
Your WaitHandle must be a ManualResetEvent, not an AutoResetEvent and you should initialise it so that it is signalled (unless you want to start your thread in a "paused" state).
You will also have to change your button handlers as follows:
private void btnPause_Click(object sender, EventArgs e)
{
waitHandle.Reset(); // Need to pause the background thread
}
private void btnContinue_Click(object sender, EventArgs e)
{
waitHandle.Set(); // Need to continue the background thread
}
This means that you must be able to pass waitHandle to the thread so that it can wait on it.
However, there are better ways of managing thread cancellation since .Net 4, namely the use of CancellationTokenSource and CancellationToken.
See this Microsoft article for details.

Related

What is the proper procedure to alert a thread the stop what it's doing and return before exiting?

What is the proper procedure to alert a running thread to stop what it's doing and return before exiting the application?
protected Thread T;
protected static ManualResetEvent mre = new ManualResetEvent(false);
protected static bool ThreadRunning = true;
public Form1()
{
InitializeComponent();
T = new Thread(ThreadFunc);
T.Start();
}
private void ThreadFunc()
{
while (ThreadRunning)
{
// Do stuff
Thread.Sleep(40);
}
mre.Set();
}
private void ExitButton_Click(object sender, EventArgs e)
{
ThreadRunning = false;
mre.WaitOne();
mre.Close();
Application.Exit();
}
Initially I had my code setup like the above. My thinking for how exit properly is as follows:
Set ThreadRunning = false so that the next time thread T checks that variable it knows to stop.
Call mre.WaitOne() to wait for thread T to say it's actually done via it calling mre.Set().
If so, then unblock and continue, dispose of mre (mre.Close()) and exit.
For some reason the above setup sometimes fails after the exit button is clicked and the whole form becomes inactive.
My new setup is below but doesn't seem entirely correct to me, for instance mre.Set() isn't going to wait for anything and Application.Exit() is immediately after it. I'm just waiting for it to fail like before, but so far it hasn't.
protected Thread T;
protected static ManualResetEvent mre = new ManualResetEvent(false);
protected static bool ThreadRunning = true;
public Form1()
{
InitializeComponent();
T = new Thread(ThreadFunc);
T.Start();
}
private void ThreadFunc()
{
while (ThreadRunning)
{
// Do stuff
Thread.Sleep(40);
}
mre.WaitOne();
mre.Close();
}
private void ExitButton_Click(object sender, EventArgs e)
{
ThreadRunning = false;
mre.Set();
Application.Exit();
}
UI hangs because you blocks UI thread with mre.WaitOne();.
If you need to wait until thread exits, you can use its IsAlive property and process application messages, you don't need application events for that:
while(_t.IsAlive)
Application.DoEvents();
There are 2 thread cancelation aproaches:
cooperative - code that is executed by thread knows that it could be cancelled and cancellation handled gracefuly, that's what you try to do here.
imperative - force thread to stop - call Thread.Abort or Interrupt, don't use that.
As #HansPassant mentioned, bool is not the best option because that compiler may optimize that and bool value could be cached and its change may not be handled by looping thread. You need to make it at least volatile or just refactor code to use CancellationSource.
Given what your thread is doing, perhaps BackgroundWorker, Timer or Producer/Consumer pattern is a better alternative to Thread, but I have too little context to recommend anything. Also it works well only if you have only 1 instance of Form1 in the application, if you have multiform application and user can open several Form1 forms, you'll have problems.
General recommendation, if you can work with instance level fields, please do that, don't use static.
Waiting for 40 msec between doing stuff creates no problems, but what if you had to wait 5 sec or more? Then canceling between each waiting would be problematic, and the right thing to do would be to cancel the awaiting itself. It is fairly easy to do it actually. Just replace Thread.Sleep(40) with Task.Delay(40, token).Wait() where token is a CancellationToken.
class Form1 : Form
{
protected readonly CancellationTokenSource _cts;
protected readonly Thread _thread;
public Form1()
{
InitializeComponent();
_cts = new CancellationTokenSource();
_thread = new Thread(ThreadFunc);
_thread.Start();
}
private void ThreadFunc()
{
try
{
while (true)
{
// Do stuff here
Task.Delay(40, _cts.Token).GetAwaiter().GetResult();
}
}
catch (OperationCanceledException)
{
// Ignore cancellation exception
}
}
private void ExitButton_Click(object sender, EventArgs e)
{
_cts.Cancel();
this.Visible = false; // Hide the form before blocking the UI
_thread.Join(5000); // Wait the thread to finish, but no more than 5 sec
this.Close();
}
}
Personally I would prefer to do the background job using a Task instead of a Thread, because it is more easily awaited without blocking the UI. This task would run lazily using thread-pool threads. The drawback is that the stuff that runs every 40 msec would not always run in the same thread, so I could have thread-safety issues to resolve.
class Form1 : Form
{
protected readonly CancellationTokenSource _cts;
protected readonly Task _task;
public Form1()
{
InitializeComponent();
_cts = new CancellationTokenSource();
_task = Task.Run(TaskFunc);
this.FormClosing += Form_FormClosing;
}
private async Task TaskFunc()
{
try
{
while (true)
{
// Do async stuff here, using _cts.Token if possible
// The stuff will run in thread-pool threads
await Task.Delay(40, _cts.Token).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
{
// Ignore cancellation exception
}
}
private void ExitButton_Click(object sender, EventArgs e)
{
this.Close();
}
private async void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (_task == null || _task.IsCompleted) return;
e.Cancel = true;
_cts.Cancel();
this.Visible = false; // Or give feedback that the form is closing
var completedTask = await Task.WhenAny(_task, Task.Delay(5000));
if (completedTask != _task) Debug.WriteLine("Task refuses to die");
_task = null;
await Task.Yield(); // To ensure that Close won't be called synchronously
this.Close(); // After await we are back in the UI thread
}
}

Background worker,Long Task or new thread for many executions in same time?

Inside my application I'm using a timer. Inside timer every 1 second I'm running a long execution code(example to create a form and printing in many printers separately) while execute this code rest application freezes for 2 secs in every single action. What is the best method for running this without influence my main ui thread??Background worker,Long Task or new thread? Also new thread requires a non single core cpu?
Here are my examples.
Thread Examle:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
/* run your code here */
Console.WriteLine("Hello, world");
}).Start();
Backgorundworker example:
BackgroundWorker.DoWork += new DoWorkEventHandler(bw_DoWork);
Task Example:
//Task should be run on other thread?
Task t = Task.Factory.StartNew(() =>
{
ThreadProcedure();
});
I'm new in c# and I whould like to learn more thing about my application's performance.
Also if there is another option more effective please let me now.
Here is an example from Background worker and timer within:
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
MessageBox.Show("Code excecution has been completed!");
timer1.Stop();
}
}

Why isn't my multithreaded app doing what it should do?

I'm using the ThreadPool to manage my threads. Separately from the UI thread I have a thread that does data retrieval and general work operations and I have a 3rd thread that updates the UI to reflect the status of requested operations.
See code below:
// ui thread
private void btnLoadClients_Click(object sender, EventArgs e)
{
// start thread 1
ThreadPool.QueueUserWorkItem(new Form1().LoadClientList);
}
// thread 1
private void LoadClientList(object state)
{
ThreadBusy = true;
ThreadAction = "Loading Clients...";
// start thread 2
ThreadPool.QueueUserWorkItem(new Form1().ShowProgress);
// get data
ClientController c = new ClientController();
List<Client> clients = c.GetClient();
foreach (Client item in clients)
{
cmbClientList.Items.Add(item.Name);
}
cmbClientList.Items.Insert(0, "Please select a client");
ThreadBusy = false;
}
// thread 2
private void ShowProgress(object state)
{
while (ThreadBusy)
{
foreach (string action in lstAction.Items)
{
// write the action that's being taken to the listbox
if (String.Compare(action, ThreadAction) != 0)
lstAction.Items.Add(ThreadAction);
}
}
}
Problem is that although ShowProgress is being hit when I set a breakpoint on it, execution isn't entering it really. The while (ThreadBusy) line isn't getting hit ever.
Have I got anything wrong here?
ThreadPool.QueueUserWorkItem(new Form1().LoadClientList);
ThreadPool.QueueUserWorkItem(new Form1().ShowProgress);
You're creating new Form1 instances every time you start a background thread, every action you take in these methods will happen to these new, "unbounded" instances, not on the one interacting with the user.
If you want to perform background work in WinForms you can leverage the BackgroundWorker class.
A really simple example:
public static class Program
{
public static void Main()
{
var backgroundWorker = new BackgroundWorker();
backgroundWorker.WorkerReportsProgress = true
backgroundWorker.Disposed += BackgroundWorker_Disposed;
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
}
private static void BackgroundWorker_Disposed(object sender, EventArgs e)
{
// Cleanup after yourself.
}
private static void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Do your things in background.
}
private static void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Notify progress.
}
private static void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// The background task is complete ("successfully" is NOT implied).
}
}
ThreadBusy property that you set to true belongs to a different Form1 object. because the thread that runs ShowProgress executes on a new instance of Form1 and its ThreadBusy property is false always. Thats why it is not entering into the while loop.
Can you try this
ThreadPool.QueueUserWorkItem(this.ShowProgress);
instead of
ThreadPool.QueueUserWorkItem(new Form1().ShowProgress);

Disable Winforms button while OnClick code executes in background

I have some code in my "button_click" action. I want to disable the button during this code working.
private void button1_Click(object sender, RoutedEventArgs e)
{
button1.IsEnabled = false;
// some code (its take about 2-5 sec)
button1.IsEnabled = true;
}
But this doesn't work. The button never disables.
You need to run the "some code" part on a background thread:
button1.Enabled = false;
Task.Factory.StartNew(() => {
// some code (its take about 2-5 sec)
}).ContinueWith(task => {
button1.Enabled = true;
}, TaskScheduler.FromCurrentSynchronizationContext());
That is because your UI locks up during the entire action.
You should write the task in some sort of background thread.
You can use the BackgroundWorker for that, but better a Task.
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += bgw_DoWork;
bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;
button.Enabled = false;
bgw.RunWorkerAsync();
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
// your task
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// update the button
button.Enabled = true;
}
Dispatcher is responsible for message pumping in WPF. Every thread has dispatcher associated with it which is responsible for queuing stuffs on that thread based on DispatcherPriority of items.
In your case GUI rendering is done on DispatcherPriority.Render but right now dispatcher is busy executing your button click event handler code so GUI rendering never happens until it finishes with your code execution. That's why you see button to be refreshed only when your handler gets executed completely.
On a sidenote what McGarnagle proposed gonna work but you can do it other way round as well by explicitly queuing empty delegate on dispatcher with priority Render which will force all queued items with priority higher or equal to Render to be processed before proceeding further. Hence, you will see refresh on your GUI:
button1.IsEnabled = false;
Application.Current.Dispatcher.Invoke((Action)(() => { }),
DispatcherPriority.Render);
// some code (its take about 2-5 sec)
button1.IsEnabled = true;

progressBar separate thread

I have question about progressbar show value.
I have this main thread
private void button1_Click(object sender, EventArgs e)
{
progress prog = new progress();
progress.progressEvent += new progress.progressEventHandler(progressEvent);
for(int i=0;i<100;i++)
{
Thread.Sleep(100);
prog.incA();
}
}
void progressEvent(object sender)
{
if (progressBar1.InvokeRequired)
{
//Tady mi to caka az kym nedobehne cyklus for a pak zacne tohleto fungovat
progressBar1.Invoke(new ChangeProgressBarValue(ProgressStep));
}
else
{
ProgressStep();
}
}
public void ProgressStep()
{
progressBar1.PerformStep();
}
public class progress
{
private ThreadStart ts;
private Thread th;
private bool status = true;
public delegate void progressEventHandler(object sender);
public static event progressEventHandler progressEvent;
private int b,a = 0;
public progress()
{
ts=new ThreadStart(go);
th = new Thread(ts);
th.IsBackground = true;
th.Start();
}
public void incA()
{
a++;
if(a==100)
status = false;
}
private void go()
{
while (status)
{
if (a != b)
{
b = a;
if (progressEvent != null)
progressEvent(this);
}
}
th.Abort();
}
}
and my problem is IF start main thread and call IncA this method call event and in event is progressbar invoke
and this invoke waiting to end main thread FOR
why waiting?
thx
Your loop in the main thread is preventing "paint" events from happening. Since you are calling your progress bar's function from withing that thread, you will never see the updates.
You need to move the code to do the incrementing to another thread entirely.
Here is a sample of what you want to do using a Button, a BackgroundWorker, and a ProgressBar:
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
for (int i = 1; i <= 100; i++)
{
backgroundWorker1.ReportProgress(i);
Thread.Sleep(100);
}
}
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
Hope this helps!
The progress bar control is a UI object, and is created on the UI thread. When you call Invoke or BeginInvoke to update it, you are asking the UI thread to do the updating.
However, the UI thread is busy - in your button CLick event handler, you have a loop which Sleep()s the thread and calls prog.IncA in a loop. So it never exits back to the main UI loop (which is what dispatches windows messages and updates the UI). Your progress bar is being updated internally, but it never gets a chance to redraw because the UI thread is "busy".
The "processing" code (that is looping and calling prog.IncA()) should not be running on the UI thread at all - you need to start it off in a separate thread and then exit your Click handler so that the UI can continue to update.
Note that this has a side effect - if your UI thread is running, then the user will be able to continue interacting with your program, and so they can click again on the button and kick off another background thread - so you have to be very careful to make sure that the user can't do anything "dangerous" in the UI while you are busy processing.
I suggest you look at some introduction-to-threading tutorials to get an idea of how to use BackgroundWorker or another mechanism for running code in a separate thread. Once you understand that, you can add a progress bar. (And note that although a progress bar sounds like the simplest thing to do, it is actually rather a difficult thing to do due to the need for the UI thread to continue running but not let the user do anything dangerous during your processing)

Categories

Resources