I am writing an application where I have a Process running in a BackgroundWorker. I would like to support cancellation from the user interface, but I don't see an easy way to do this.
The Process is actually a fairly long running command line exe. The output is getting redirected asynchronously via the Progress.OutputDataReceived event and is being used to report progress to the GUI.
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
using (var process = new Process())
{
//...
process.Start()
//...
process.WaitForExit();
}
}
private void CancelWorker()
{
worker.CancelAsync();
// where to actually listen for the cancellation???
}
There doesn't appear to be a way to have the process "listen" for any input from the main thread aside from the StandardInput, but that won't work unless the app itself will response to a specific input to abort.
Is there a way to cancel a process based on a cancel request from the main thread?
For the purposes of my of the EXE running in the process, I can just call Process.Close() to exit without any side-effects, but the Process object is only known to the worker_DoWork() method, so I'll need to keep track of the Process instance for cancellation purposes... that's why I'm hoping there might be a better way.
(if it matters, I am targeting .NET 3.5 for compatibility issues.)
For cooperative cancellation, you need to listen to BackgroundWorker.CancellationPending
in BackgroundWorker.DoWork
event.
How to: Use a Background Worker
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
using (var process = new Process())
{
//...
process.Start()
//...
while(true)
{
if ((sender as BackgroundWorker).CancellationPending && !process.HasExited)
{
process.Kill();
break;
}
Thread.Sleep(100);
}
process.WaitForExit();
}
}
try this, this might be help you, in easy way
private System.Threading.TimerCallback worker;
private System.Threading.Timer workertimer ;
private void worker_DoWork()
{
//You codes
}
private void StartWorker()
{
worker = new System.Threading.TimerCallback(worker_DoWork);
workertimer = new System.Threading.Timer(worker, null, 1000, 1000);
}
private void CancelWorker()
{
worker.Dispose();
}
Related
My question is i want to execute some operations like fetching the data ( format is string )from some URL . and i want run this process to be background. i have to call this operations whenever user needs this. like if a user clicks a button specified for this operation, it should execute the function and provide result to that user. Problem is when ever executing this no other program should not get interrupted. I want to run this Asynchronous way . i want to return the result which is downloaded from the URL
Here is my solution using thread
namespace xyz
{
public class newWinForm : Form
{
SomeClass someClass = new SomeClass();
public newWinForm()
{
Thread backgroundThread = new Thread(DoWork);
backgroundThread.IsBackground = true;
backgroundThread.Start();
}
void DoWork()
{
try
{
Console.WriteLine("Doing some work...");
using(WebClient cl = new WebClient())
{
string result = cl.DownloadString("http://www.......com");
}
Thread.Sleep(1000);
}
finally
{
Console.WriteLine("This should be always executed");
}
}
private void getDataFrmUrlButton_Click(object sender, EventArgs e)
{
Thread backgroundThread = new Thread(DoWork);
backgroundThread.IsBackground = true;
backgroundThread.Start();
}
}
You can use backgroundworker class in order to achieve your task
private BackgroundWorker bg1 = new BackgroundWorker();
bg1.DoWork += bg1_DoWork;
private void bg1_DoWork(object sender, DoWorkEventArgs e)
{
//the function you want to execute
}
In this case your operation is I/O bound, so an asynchronous approach is best. To do this you can use the async keyword on your events.
private async void getDataFrmUrlButton_Click(object sender, EventArgs args)
{
using(var client = new WebClient())
{
string result = await client.DownloadStringTaskAsync(uri);
// Do stuff with data
}
}
This post gives some good resources for more information on async/await.
If you want a more enterprise based solution you can have a look at Hangfire (https://www.hangfire.io/).
While normally targeted at ASP.NET solutions you can also run it as part of a windows service and use that in conjunction with your WinForm based application(s). It will allow you to easily hand off long running tasks and track them even if you don't want to to use TPL to do it yourself.
I have developed a socket program . I have the problem with the client side socket program it gets data from multiple servers,one at a time and update the details in listview. It happens inside a infinite loop.
while(true)
{
}
I want to exit this this loop in the middle period, I used button click event to do that
foreach (Process myProc in Process.GetProcesses())
{
if (myProc.ProcessName == "procees name")
{
myProc.Kill();
}
}
but it's too slow, I want to pause that process and kill it. Help me to pause currently running process.
Since you mention the process is your own application, you can just exit the application yourself instead of killing the application. Your question turns out more to be "how can I exit my program".
Firstly, your button may not seem responsive since you're running an infinite loop. One (bad) way of doing it is like this:
private bool _exit = false; //member variable
while(true && !_exit)
{
Application.DoEvents();
}
Application.DoEvents is important to make your application keep listening to other actions. And then,
private void btn_Click(object sender, EventArgs e)
{
_exit = true;
}
The ideal way imo is to transfer the job of getting data from servers to a background process. May be something like this:
BackgroundWorker _backgroundWorker = new BackgroundWorker(); //member field
void Listen()
{
_backgroundWorker.WorkerSupportsCancellation = true;
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.DoWork += (sender, e) => { while(condition)//bla bla; }
_backgroundWorker.RunWorkerAsync();
}
And then upon your cancellation click,
private void btn_Click(object sender, EventArgs e)
{
_backgroundWorker.CancelAsync();
}
There is no such feature to pause running process, so the answer is no.
If this would be possible you could change every process, and that is something which all software builders try to prevent.
You will need some way around.
However, if you have time you can try
http://www.c-sharpcorner.com/uploadfile/mmehta/multithreading311162005045743am/multithreading3.aspx
http://www.codeproject.com/Articles/2042/Using-events-for-thread-synchronization
If you want to handle multiple simultaneous socket connections, I'd suggest using SocketAsyncEventArgs instead of traditional while (true).
Take a look at this article:
C# SocketAsyncEventArgs High Performance Socket Code
And the simplest (but not flawless) solution that usually comes with the while loop is something like this:
private volatile bool _running = true;
...
while (_running)
{
// Do stuff
}
...
public void ButtonClick(object sender, EventArgs e)
{
_running = false;
}
Depending on your application (how many threads, what ui library), you could just use
Application.Exit. Perhaps you should set the IsBackground property of your worker threads when creating them.
Just imagine what would happen, if it were possible to pause the process. The user clicks the button, your program pauses the current process, and than there is nothing to do, because you just paused yourself. The code to kill the process would never run.
You could suspend all the threads of a remote process.
http://www.codeproject.com/Articles/2964/Win32-process-suspend-resume-tool
When a user clicks on Run, the application runs through a lot of code to generate a model and display it in a Chart. The Run takes about 1-2 minutes to run. I also have a Cancel button that gets enabled after the Run button is clicked. I am working with DotSpatial, so my buttons are on a plugin panel in a ribbon UI. The click event on the Run and Cancel start in the plugin, which calls the back-end class's code Run and Click.
When the user hits cancel after the run starts, there is a delay, but the cancel method is invokes and executes, but the run never stops and we eventually see the chart display. So, I'm thinking I need a separate thread for the Run. I'm fairly new to programming, and never worked with Threading. I've looked into it and added the below code, but my thread method isn't running. Here's my code:
The Run button is clicked:
This is at the top:
//check to see if RunModel thread needs to stop or continue
private volatile bool stopRun = false;
private Thread runThread;
Then this is the method that's called from the click event:
public void btnRun_testingThread(object sender, EventArgs e)
{
//create a new thread to run the RunModel
if (runThread == null)
{
//we don't want to stop this thread
stopRun = false;
runThread = new Thread(RunModel);
runThread.Start(); <--this isn't doing anything
}
So, I would think that when the code gets to the runThread.Start(), it would jump into my RunModel method and start running through the code. But it doesn't. Additionally, I'll want to cancel out of this thread (once I have it working correctly), so I have this, which gets called from the cancel click method:
private void StopRunThread()
{
if (runThread != null)
{
//we want to stop the thread
stopRun = true;
//gracefully pause until the thread exits
runThread.Join();
runThread = null;
}
}
Then the this is the RunModel() where I'm checking occasionally to see if the stopRun bool has changed.
public void RunModel()
{
...some code.....
//check to see if cancel was clicked
if (stopRun)
{
....clean up code....
return;
}
....some more code....
//check to see if cancel was clicked
if (stopRun)
{
....clean up code....
return;
}
}
And the cancel button click method:
public void btnCancel_Click(Object sender, EventArgs e)
{
stopRun = true;
StopRunThread();
//the model run has been canceled
....some code.....
}
Any help on getting the thread.start to actually run the Run method? Then do I need to constantly check the volatile bool in the run in order to clean everything up if it's being stopped? Thanks!
I think you'd be best looking at the BackgroundWorker - this essentially runs separately but can watch out for cancellation commands. Make sure you add 'WorkerSupportCancellation' when you initialise it:
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); // This does the job ...
backgroundWorker1.WorkerSupportsCancellation = true; // This allows cancellation.
Then on click you can start your process:
public void btnRun_testingThread(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
Your cancel button can issue a cancellation request:
public void btnCancel_Click(Object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
}
Then your worker can monitor for this as it's doing it's work ...
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
if (backgroundWorker1.CancellationPending)
{
break;
}
else
{
// Do whatever you're doing.
}
}
e.Result = backgroundWorker1.CancellationPending ? null : orders;
}
You can enhance this further by adding progress bars etc., but that gets a bit more complicated so I won't go into it here.
Considering new info provided in commend I believe you just missed a start of the RunModel() method in debugger because of wrong assumption regarding thread.Start() method behaviour.
Please see a note from MSDN, Thread.Start Method
Once a thread is in the ThreadState.Running state, the operating
system can schedule it for execution. The thread begins executing
at the first line of the method represented by the ThreadStart or
ParameterizedThreadStart delegate supplied to the thread constructor.
Small demonstration that thread start takes some time bits, for me it starts in 38-40 milliseconds:
Stopwatch watch = new Stopwatch();
Thread thread = new Thread((ThreadStart)watch.Stop);
thread.Start();
watch.Start();
Thread.Sleep(5000);
double startedAfter = watch.ElapsedMilliseconds;
Since .NET Framework 4.0 consider using TPL Tasks rather than threads explicitly, some pros:
You can easily synchronize with UI thread by passing in a Task UI Thread synchronization context
You can easily stop a Taks using CancellationToken
I have a BackgroundWorker DoWork function as follows
private void WorkerGetFeedData(object sender, DoWorkEventArgs args)
{
_feed.FetchUserData(_userNameCollection);
}
The FetchUserData is a function in another class(whose object is _feed) in another project in the same solution. The data fetch process takes considerable time and I'd like for the user to be able to cancel the process if necessary. How do I convey a cancel operation from the user to a function call elsewhere and just stop it?
You can use BackgroundWorker.CancelAsync method. Here's more info with example: MSDN
To be more exact to your problem, pass the worker to FetchUserData. It is the sender parameter. Then in the FetchUserData function you can check if the flag BackgroundWorker.CancellationPending is set and finish your method.
void FetchUserData(IEnumerable<Users> userNameCollection, BackgroundWorker worker)
{
// ...
if(worker.CancellationPending)
{
// Finish method..
}
}
And the WorkerGetFeedData method:
private void WorkerGetFeedData(object sender, DoWorkEventArgs args)
{
var worker = sender as BackgroundWorker;
if(worker != null)
_feed.FetchUserData(_userNameCollection, worker);
}
Send a message (event) to the worker thread that changes a boolean, indicating that the worker thread should end/cancel itself.
Edit: I was a bit quick reading your question, missing the important part. While trying to make up I found this interesting article which might help:
http://ondotnet.com/pub/a/dotnet/2003/02/18/threadabort.html
It does work when simulating a long running process with Thread.Sleep(), being at work I dont have time right now to write code to test it on a proper application/long running task.
class Program
{
static void Main(string[] args)
{
Thread thread = new Thread(new ThreadStart(Foo));
thread.Start();
Console.ReadKey();
thread.Abort(); // cause ThreadAbortException to be thrown
Console.ReadKey();
}
static void Foo()
{
try
{
while( true )
{
Console.WriteLine("Long running process...");
Thread.Sleep(100000);
}
}
catch( ThreadAbortException ex )
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine("Thread Closing ...");
}
}
}
The problem with this approach is - it uses Thread.Abort() - which interrupts the thread no matter what it is doing. This can lead to left open handles, memory leaks, etc. So while it may help it would most likely be very unwise to use.
Ian Griffiths supposes that another way to (force) cancel a thread would be to run it in its own, seperate process: http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation which you can kill whenever without affecting your process's internal state.
Is there a way to directly "restart" a background worker?
Calling CancelAsync() followed by RunWorkerAsync() clearly won't do it as their names imply.
Background info:
I have a background worker which calculates a total in my .net 2.0 Windows Forms app.
Whenever the user modifies any value which is part of this total I'd like to restart the background worker in case it would be running so that directly the latest values are considered.
The backgriound work itself does not do any cancleing.
When you call bgw.CancelAsync it sets a flag on the background worker that you need to check yourself in the DoWork handler.
something like:
bool _restart = false;
private void button1_Click(object sender, EventArgs e)
{
bgw.CancelAsync();
_restart = true;
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 300; i++)
{
if (bgw.CancellationPending)
{
break;
}
//time consuming calculation
}
}
private void bgw_WorkComplete(object sender, eventargs e) //no ide to hand not sure on name/args
{
if (_restart)
{
bgw.RunWorkerAsync();
_restart = false;
}
}
There are a couple of options, it all depends on how you want to skin this cat:
If you want to continue to use BackgroundWorker, then you need to respect the model that has been established, that is, one of "progress sensitivity". The stuff inside DoWork is clearly required to always be aware of whether or not the a pending cancellation is due (i.e., there needs to be a certain amount of polling taking place in your DoWork loop).
If your calculation code is monolithic and you don't want to mess with it, then don't use BackgroundWorker, but rather fire up your own thread--this way you can forcefully kill it if needs be.
You can hook the change event handler for the controls in which the values are changed and do the following in the handler:
if(!bgWrkr.IsBusy)
//start worker
else if(!bgWrkr.CancellationPending)
bgWrkr.CancelAsync();
Hope it helps you!
I want to leave my requests running, but no longer care about the results. I override the value of the background worker (my busy spinner is using the isBusy flag).
private void SearchWorkerCreate() {
this.searchWorker = new BackgroundWorker();
this.searchWorker.DoWork += this.SearchWorkerWork;
this.searchWorker.RunWorkerCompleted += this.SearchWorkerFinish;
}
private void SearchWorkerStart(string criteria){
if(this.searchWorker.IsBusy){
this.SearchWorkerCreate();
}
this.searchWorker.RunWorkerAsync(criteria);
this.OnPropertyChanged(() => this.IsBusy);
this.OnPropertyChanged(() => this.IsIdle);
}
May this method help someone... I've created a function to reset the backgroundworker in one method. I use it for task to do periodically.
By creating a Task, the backgroundworker is can be stopped with the CancelAsync and restarted inside the Task. Not making a Task wil start the backgroundworker again before it is cancelled, as the OP describes.
The only requirement is that your code runs through some loop, which checks the CancellationPending every period of time (CheckPerMilliseconds).
private void ResetBackgroundWorker()
{
backgroundWorker.CancelAsync();
Task taskStart = Task.Run(() =>
{
Thread.Sleep(CheckPerMilliseconds);
backgroundWorker.RunWorkerAsync();
});
}
Inside the backgroundworker I use a for-loop that checks the CancellationPending.
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while(true)
{
if (backgroundWorker.CancellationPending)
{
return;
}
//Do something you want to do periodically.
for (int i = 0; i < minutesToDoTask * 60; i++)
{
if (backgroundWorker.CancellationPending)
{
return;
}
Thread.Sleep(CheckPerMilliseconds);
}
}
}