Thread.Suspend() method is obsolete as you know. I want to suspend thread immidiately when button click event comes. I used Thread.Suspend() and it works perfect but everyone suggest that using Thread.Suspend() method is not a good method to suspend the task. I used a flag to suspend the task but every time when a button click event comes, i have to wait to exit from task. I used Thread.IsAlive flag to wait the thread to exit but this method freezes form.
void ButtonClickEvent(object sender, ButtonClickEventArgs e)
{
TheadExitFlag = false;
if(MyThread != null)
{
while(MyThread.IsAlive);
//MyThread.Suspend();
}
}
void MyTask(void)
{
while(TheadExitFlag)
{
// some process
Thread.Sleep(5000);
}
}
How can i suspend the thread immidiately?
There is no alternative with the same functionality, AFAIK. I am not sure if the problems with an OS Suspend() could be worked around within the language/libraries, but no attempt has been made to do so, so maybe it's too difficult or even sensibly impossible.
Until such an alernative exists, you are reduced to polling for a suspend flag and then waiting on some synchronization object for a 'resume' signal. I have used AutoResetEvent for this.
Use a ManualResetEvent to toggle between a running and idle state.
ManualResetEvent run = new ManualResetEvent(true);
void ResumeButton_Click(object sender, ButtonClickEventArgs e)
{
run.Set();
PauseButton.Enabled = true;
ResumeButton.Enabled = false;
}
void PauseButton_Click(object sender, ButtonClickEventArgs e)
{
run.Reset();
PauseButton.Enabled = false;
ResumeButton.Enabled = true;
}
void MyTask(void)
{
while (run.WaitOne()) // Wait for the run signal.
{
// Do work here.
}
}
There is an approximate solution to this problem at https://stackoverflow.com/a/45786529/3013473 using AspectJ and wait/notify.
Related
i have a BackgroundWorker that execute work in the background. the work is run some .exe application in command prompt and wait for output for display. sometimes the .exe app is stack or takes a lot of time. i want to stop the worker after one minute in case it is still running.
the issue is that i have a progress bar that runs in the main thread for 1 minute. i want to stop the worker when the progress bar is full (after 1 minute) from the main thread (UI). here is my code:
private void btnTest_Click(object sender, RoutedEventArgs e)
{
wTest = new BackgroundWorker();
wTest .DoWork += new DoWorkEventHandler(wTest _DoWork);
wTest .RunWorkerCompleted += wTest _RunWorkerCompleted;
wTest .WorkerReportsProgress = true;
wTest .WorkerSupportsCancellation = true;
wTest .RunWorkerAsync();
while (pbTest.Value < 91)
{
if (!wTest.CancellationPending)
{
pbTest.Value = (pbTest.Value + 100/60);
Thread.Sleep(1000);
}
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background,
new ThreadStart(delegate { }));
}
}
void wTest_DoWork(object sender, DoWorkEventArgs e)
{
//call .exe application and wait for output
}
how can i do it?
You will need to do two things to enable work cancellation of your BackgroundWorker. First, you will need to check for the BackgroundWorker.CancellationPending property in your DoWork handler method:
private void wTest_DoWork(object sender, DoWorkEventArgs e)
{
//call .exe application and wait for output
if (worker.CancellationPending)
{
e.Cancel = true;
}
}
Then, when you want to cancel the work, you should call this on your BackgroundWorker:
backgroundWorker.CancelAsync();
However, as you are not using the BackgroundWorker as it was meant to be used, I don't think that this will work for you. If you are waiting for the third party application to start, then you won't be able to set the e.Cancel property to true.
To be honest, I can't quite understand why you would use a BackgroundWorker just to start a process anyway. The Process.Start method takes no time to complete as it doesn't wait for any response. In my opinion, you'd be better off monitoring the Process.Exited event and calling the Process.Kill method instead.
If you are using .net 4.5, you can use the Task class and the associated CancellationTokeSource and CancellationToken classes. Note that tasks support reporting progress through the IProgress interface. Stephen Cleary has a good example on this.
If the work you were doing does not provide an asynchronous interface you can use Task.Run to execute it and pass a CancellationToken to monitor for cancellation. As you are doing the work you need to monitor the token for cancellation. One way to do this is to call ThrowIfCancellationRequested which will throw a OperationCancelledException if Cancel has been called on the CancellationTokenSource. CancellationTokenSource also supports cancellation after a certain time, which will be handy for your scenario.
private CancellationTokenSource cts;
private void btnTest_Click(object sender, RoutedEventArgs e)
{
if(cts == null)
{
cts = new CancellationTokenSource(new TimeSpan(0, 0, 60)); // cancel after 60 seconds
}
await Task.Run( () => Work(), cts.Token);
cts = null;
}
void Work(CancellationToken token)
{
// do work
token.ThrowIfCancellationRequested();
// do work
}
What you need to do is have your DoWork delegate check for e.Cancel (in DoWorkEventArgs) property bring set to true. If DoWork is blocking, like waiting for StandardOutput, then that simply wont be possible.
Another approach would be to pass Process.WaitForExit an int stating how long it should wait for output:
process.WaitForExit(60000);
I am writing a simple C# program that attempts to do something every x amount of seconds using System.Forms.Timer
The tick event calls a method that starts a new thread and disables the timer, then when the thread is done with its work, it enables the timer again, but the problem is, now it doesn't tick after it's been enabled.
static System.Windows.Forms.Timer testtimer = new System.Windows.Forms.Timer();
static void Main()
{
testtimer.Tick += testtimertick;
testtimer.Interval = 5000;
testtimer.Enabled = true;
testtimer.Start();
while (true)
{
Application.DoEvents(); //Prevents application from exiting
}
}
private static void testtimertick(object sender, System.EventArgs e)
{
testtimer.Enabled = false;
Thread t = new Thread(dostuff);
t.Start();
}
private static void dostuff()
{
//Executes some code
testtimer.Enabled = true; //Re enables the timer but it doesn't work
testtimer.Start();
}
As #grzenio said, it appears that your issue has to do with the fact that you are making cross thread calls to a Windows Form Control that was created on a different thread.
If you are using .NET 4.5 (C# 5.0), I would suggest looking at the async/await keywords, a good introduction can be found at Stephen Cleary's Blog
An example of how you could use async and await with your legacy "DoStuff":
private async void _Timer_Tick(object sender, EventArgs e)
{
_Timer.Enabled = false;
await Task.Run((() => DoStuff()));
_Timer.Enabled = true;
}
Things to notice:
async was added to the Timer_Tick event's signature.
The await keyword along with Task.Run was used to asynchronously run the DoStuff.
When using these keywords, the DoStuff will be run asynchronously and once DoStuff returns, it will continue on the line after await using the context of the thread that originally called Tick.
Don't use a GUI timer without a GUI. Don't spin with DoEvents because you are burning 100% of a CPU core with that. Use a System.Threading.Timer. It will just work.
Windows Forms controls are not thread safe, you should make sure you use them on the UI thread, see e.g. C# Windows Forms Application - Updating GUI from another thread AND class?
You can use System.Threading.Timer to do what you want to do, using the Change Method to set the time and the Period, Just restart it when you finish your work.
class Program
{
static System.Threading.Timer testtimer;
static void Main(string[] args)
{
testtimer = new System.Threading.Timer(testtimertick);
testtimer.Change(5000,0);
Console.ReadLine();
}
private static void testtimertick(object sender)
{
Thread t = new Thread(dostuff);
t.Start();
}
private static void dostuff()
{
//Executes some code
Thread.Sleep(2000);
Console.WriteLine("Tick");
testtimer.Change(5000, 0);
}
}
static System.Windows.Forms.Timer testtimer = new System.Windows.Forms.Timer();
static void Main()
{
testtimer.Tick += testtimertick;
testtimer.Interval = 5000;
testtimer.Enabled = true;
while (true)
{
Application.DoEvents(); //Prevents application from exiting
}
}
private static void testtimertick(object sender, System.EventArgs e)
{
Thread t = new Thread(dostuff);
t.Start();
}
private static void dostuff()
{
testtimer.Enabled = false;
//Executes some code
testtimer.Enabled = true; //Re enables the timer but it doesn't work
testtimer.Start();
}
I had a similar issue just now. I was disabling the timer and enabling again whenever I want.
The next time when I enable, it won't work.
I tried disposing the Timer object when I want to disable and creating new instance of it each time I want to enable it. Didn't work though.
Figured out a solution then. I'm removing the event which is configured in testtimer.Tick, and then adding it back when I want to enable the timer.
So the timer internally will be always instantiated with valid values and have its property Enabled = true. The only difference is that it won't have anything actually to perform whenever a tick event triggers.
This would imitate disabling and enabling the timer and makes it working as good as you control like Enabled = false / true.
If you really want to stick to the GUI timer, and start it from non UI thread, you can try to do similar stuff, then write to GUI from non UI thread.
Not the ideal solution, I know.
this.Invoke((MethodInvoker)delegate
{
refreshTimer.Enabled = true;
refreshTimer.Start();
});
I'm trying to use a Background Worker in a WPF application. The heavy lifting task uses WebClient to download some HTML and parse some info out of it. Ideally I want to do that downloading and parsing without locking the UI and placing the results in the UI once it's done working.
And it works fine, however, if I quickly submit the "download and parse" command, I get the error:
This BackgroundWorker is currently busy and cannot run multiple tasks
concurrently
So I did some Googling and it seems that I can enable the .WorkerSupportsCancellation property of the background worker and just .CancelAsync(). However, this doesn't work as expected (canceling the current download and parse).
I still get the above error.
Here's my code:
//In window constructor.
_backgroundWorker.WorkerSupportsCancellation = true;
_backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
//Declared at class level variable.
BackgroundWorker _backgroundWorker = new BackgroundWorker();
//This is the method I call from my UI.
private void LoadHtmlAndParse(string foobar)
{
//Cancel whatever it is you're doing!
_backgroundWorker.CancelAsync();
//And start doing this immediately!
_backgroundWorker.RunWorkerAsync(foobar);
}
POCOClassFoo foo = new POCOClassFoo();
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//This automagically sets the UI to the data.
Foo.DataContext = foo;
}
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//DOING THE HEAVY LIFTING HERE!
foo = parseanddownloadresult()!
}
Calling CancelAsync will still fire the RunWorkerCompleted event. In this event, you need to make sure that CancelAsync has not been called, by checking e.Cancelled. Until this event fires, you cannot call RunWorkerAsync.
Alternatively, I would recommend you do what Tigran suggested and create a new BackgroundWorker each time.
Further more, I would recommend storing the results of_backgroundWorker_DoWork in e.Result, then retrieve them from the same in _backgroundWorker_RunWorkerCompleted
Maybe something like this
BackgroundWorker _backgroundWorker;
private BackgroundWorker CreateBackgroundWorker()
{
var bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += _backgroundWorker_DoWork;
bw.RunWorkerCompleted += new _backgroundWorker_RunWorkerCompleted;
return bw.
}
private void LoadHtmlAndParse(string foobar)
{
//Cancel whatever it is you're doing!
if (_backgroundWorer != null)
{
_backgroundWorker.CancelAsync();
}
_backgroundWorker = CreateBackgroundWorker();
//And start doing this immediately!
_backgroundWorker.RunWorkerAsync(foobar);
}
//you no longer need this because the value is being stored in e.Result
//POCOClassFoo foo = new POCOClassFoo();
private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
//Error handling goes here.
}
else
{
if (e.Cancelled)
{
//handle cancels here.
}
{
//This automagically sets the UI to the data.
Foo.DataContext = (POCOClassFoo)e.Result;
}
}
private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//DOING THE HEAVY LIFTING HERE!
e.Result = parseanddownloadresult()!
}
The thing is that CancelAsync() does what it climes: cancel in async way. That means that it will not stop immediately, but after some time. That time can never be calculated or predicted, so you have a couple of options:
Wait until this backround worker stops really, by waiting in cycle until IsBusy property of it becomes false
Or, I think, better solution is to start another background worker, considering that request of cancelation was already sent to the first one, so it will be soon or later stop. In this case, you need to know from which background worker data comes, in order to process it or not, cause on start of second the first one will still run and pump the data from WebService.
Hope this helps.
CancelAsync returns before the worker cancels and stops its work. Hence, your RunWorkerAsync call is starting before the worker is ready, and you're getting that error. You'll need to wait for the worker to be ready first.
When I'm not interested in tracking progress of an async operation, I tend to prefer to just slap a lambda at ThreadPool.QueueUserWorkItem instead of instantiating and setting up a background worker that I have to check the state of to be able to reuse in a sane way.
You need to verify before you kicks in.
f( !bw.IsBusy )
bw.RunWorkerAsync();
else
MessageBox.Show("Can't run the bw twice!");
You are calling CancelAsync without waiting for the background worker to actually cancel the work. Also you must have your own logic for cancelling the work. There is a good example on MSDN which shows how to do it. Basically in your parseanddownloadresult() method you need to check the CancellationPending property.
I have this code to pause and resume a thread:
public partial class frmMain : Form
{
(...)
ManualResetEvent wait_handle = new ManualResetEvent(true);
(...)
}
private void frmMain_Shown(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(TheLoop));
}
private void TheLoop(object stateinfo)
{
bool hasInfo = true;
while (doLoop)
{
wait_handle.WaitOne();
bool hasLines = GetInfo();
if (hasLines)
{
//Consuming time Operation 1
System.Threading.Thread.Sleep(7000);
if (CurrentLine < line.Count - 1)
CurrentLine++;
else
{
bool hasInfo2 = GetInfo2();
if (hasInfo2)
{
//Consuming time Operation 2
System.Threading.Thread.Sleep(7000);
}
CurrentLine = 0;
}
}
else
System.Threading.Thread.Sleep(40000); //Wait to query again
}
}
private void btnPauseResume_Click(object sender, EventArgs e)
{
if (btnPauseResume.Text == "Pause")
{
btnPauseResume.Text = "Resume";
wait_handle.Reset();
}
else
{
btnPauseResume.Text = "Pause";
wait_handle.Set();
}
}
The code above shows a cycle information, it works find to pause and resume the "first consuming time operation" but doesn't work for the second one, if I press the button to pause the thread in the second consuming time operation, this one continues and when the first one appears again, then it pauses there.
What am I missing here?
Thx
Have you considered using a Background Worker instead since you are using WinForms? It would probably be easier than trying to 'Pause' a thread. You can check the CancellationPending property to see if a user has elected to cancel the operation. The link has a good sample to look at.
I have never seen someone pausing a thread. Create a delegate and event inside the class or method that you are executing on a separate threat. Execute that event whenever you wish to pause your thred.
There is not any reason that I can see that would prevent a second call to WaitOne from working if placed before the 2nd time consuming operation. Since you are using a ManualResetEvent the wait handle's state will persist until either Set or Reset is called. That means if you resume the thread by calling Set then both calls to WaitOne will pass through. Likewise, if you pause the thread by calling Reset then both calls to WaitOne will block. Of course, it will not be possible to predict where the worker thread will pause if there is more than one call to WaitOne.
Got it guys! the thing is where you put the WaitOne(). For instance, if I have a While Loop (like my example) if I put the wait before it, no matter how many times I hit the pause button, it won't stop the thread, it's logic since the loop already began, but if I put it at the end, then it will work.
Appreciated your help.
When my C# application closes it sometimes gets caught in the cleanup routine. Specifically, a background worker is not closing. This is basically how I am attempting to close it:
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
backgroundWorker1.CancelAsync();
while (backgroundWorker1.IsBusy) ; // Gets stuck here.
}
Is there a different way that I should be doing this? I am using Microsoft Visual C# 2008 Express Edition. Thanks.
ADDITIONAL INFORMATION:
The background worker does not appear to be exiting. This is what I have:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!backgroundWorker1.CancellationPending)
{
// Do something.
}
}
I've also modified the cleanup code:
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
while (backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
System.Threading.Thread.Sleep(1000);
}
}
Is there something else that I should be doing?
Some pretty good suggestions, but I don't believe they address the underlying issue: canceling a background task.
Unfortunately, when using BackgroundWorker, termination of your task depends on the task itself. The only way your while loop will terminate, is if your background task checks its Cancel property and returns or breaks from its current process.
Example Base
For example, consider
private readonly BackgroundWorker worker = new BackgroundWorker ();
public void SomeFormEventForStartingBackgroundTask ()
{
worker.DoWork += BackgroundTask_HotelCalifornia;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync ();
}
// semantically, you want to perform this task for lifetime of
// application, you may even expect that calling CancelAsync
// will out and out abort this method - that is incorrect.
// CancelAsync will only set DoWorkEventArgs.Cancel property
// to true
private void BackgroundTask_HotelCalifornia (object sender, DoWorkEventArgs e)
{
for ( ; ;)
{
// because we never inspect e.Cancel, we can never leave!
}
}
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
worker.CancelAsync();
// [politely] wait until background task terminates
while (worker.IsBusy);
}
This is what is happening by default. Now, maybe your task isn't an infinite loop, perhaps it is just a long-running task. Either way, your main thread will block [actually it is spinning, but whatevs] until the task completes, or doesn't as the case may be.
If you have personally written and can modify the task, then you have a few options.
Example Improvement
For instance, this is a better implementation of the above example
private readonly BackgroundWorker worker = new BackgroundWorker ();
// this is used to signal our main Gui thread that background
// task has completed
private readonly AutoResetEvent isWorkerStopped =
new AutoResentEvent (false);
public void SomeFormEventForStartingBackgroundTask ()
{
worker.DoWork += BackgroundTask_HotelCalifornia;
worker.RunWorkerCompleted += BackgroundTask_Completed;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync ();
}
private void BackgroundTask_HotelCalifornia (object sender, DoWorkEventArgs e)
{
// execute until canceled
for ( ; !e.Cancel;)
{
// keep in mind, this task will *block* main
// thread until cancel flag is checked again,
// so if you are, say crunching SETI numbers
// here for instance, you could still be blocking
// a long time. but long time is better than
// forever ;)
}
}
private void BackgroundTask_Completed (
object sender,
RunWorkerCompletedEventArgs e)
{
// ok, our task has stopped, set signal to 'signaled' state
// we are complete!
isStopped.Set ();
}
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
worker.CancelAsync();
// [politely] wait until background task terminates
isStopped.WaitOne ();
}
While this is better, it's not as good as it could be. If you can be [reasonably] assured your background task will end, this may be "good enough".
However, what we [typically] want, is something like this
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
worker.CancelAsync();
// [politely] wait until background task terminates
TimeSpan gracePeriod = TimeSpan.FromMilliseconds(100);
bool isStoppedGracefully = isStopped.WaitOne (gracePeriod);
if (!isStoppedGracefully)
{
// KILL! KILL! KILL!
}
}
Alas, we cannot. BackgroundWorker does not expose any means of forceful termination. This is because it is an abstraction built on top of some hidden thread management system, one which could potentially destabalize other parts of your application if it were forcefully terminated.
The only means [that I have seen at least] to implement the above is to manage your own threading.
Example Ideal
So, for instance
private Thread worker = null;
// this time, 'Thread' provides all synchronization
// constructs required for main thread to synchronize
// with background task. however, in the interest of
// giving background task a chance to terminate gracefully
// we supply it with this cancel signal
private readonly AutoResetEvent isCanceled = new AutoResentEvent (false);
public void SomeFormEventForStartingBackgroundTask ()
{
worker = new Thread (BackgroundTask_HotelCalifornia);
worker.IsBackground = true;
worker.Name = "Some Background Task"; // always handy to name things!
worker.Start ();
}
private void BackgroundTask_HotelCalifornia ()
{
// inspect cancel signal, no wait period
//
// NOTE: so cheating here a bit, this is an instance variable
// but could as easily be supplied via parameterized thread
// start delegate
for ( ; !isCanceled.WaitOne (0);)
{
}
}
private void App_FormClosing(object sender, FormClosingEventArgs e)
{
// [politely] request termination
isCanceled.Set ();
// [politely] wait until background task terminates
TimeSpan gracePeriod = TimeSpan.FromMilliseconds(100);
bool isStoppedGracefully = worker.Join (gracePeriod);
if (!isStoppedGracefully)
{
// wipe them out, all of them.
worker.Abort ();
}
}
And that there, is a decent introduction on thread management.
Which is best suited for you? Depends on your application. It is probably best not to rock the boat, and modify your current implementation to ensure that
your background task inspects and respects the Cancel property
your main thread waits for completion, as opposed to polling
It is very important to compare and evaluate the pros and cons of each approach.
If you must control and guarantee termination of someone else's tasks, then writing a thread management system that incorporates the above may be the way to go. However you would lose out on out-of-box features like thread pooling, progress reporting, cross-thread data marshalling [worker does that, no?], and a bunch of other stuff. Not to mention, "rolling your own" is often error prone.
Anyway, hope this helps :)
Kevin Gale is correct in stating that your BackgroundWorker's DoWork handler needs to poll for CancellationPending and return if a cancellation is requested.
That being said, if this is happening when your application is shutting down, you can just ignore it safely, as well. BackgroundWorker uses a ThreadPool thread, which is, by definition, a background thread. Leaving this running will not prevent your application from terminating, and the thread will automatically be torn down when your application shuts down.
In the background worker thread you need to check the BackgroundWorker.CancellationPending flag and exit if it is true.
The CancelAsync() just sets this flag.
Or to put it another way. CancelAsync() doesn't actually cancel anything. It won't abort the thread or cause it to exit. If the worker thread is in a loop and checks the CancellationPending flag periodically it can catch the cancel request and exit.
MSDN has an example here although it doesn't use a loop in the worker routine.
This code is guaranteed to deadlock when the BGW is still running. BGW cannot complete until its RunWorkerCompleted event finished running. RunWorkerCompleted cannot run until the UI thread goes idle and runs the message loop. But the UI thread isn't idle, it is stuck in the while loop.
If you want the BGW thread to complete cleanly, you have to keep your form alive. Check this thread to see how to do that.
Try:
if (this.backgroundWorker1.IsBusy) this.backgroundWorker1.CancelAsync();