I have some code inside a background worker DoWork event which check if a process is running or not. The code in the DoWork does the following:
-> If the process is not running, check again twice
-> If the process is running, check if it is responding
-> If the process is running and respoding, do nothing
-> If the process is running and not responding, restart the process
void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
int numberTrials = 0;
bool isNotRunning = false;
while (isNotRunning = (someProcess.Length == 0) && numberTrials < 3)
{
Debug.WriteLine(String.Format("numTrial = {0}", numberTrials.ToString()));
Thread.Sleep(3000);
++numberTrials;
}
if (isNotRunning)
{
Debug.WriteLine("Start Task");
someProcess.Start();
}
else
{
if(!someProcess.IsKioskResponding)
{
Debug.WriteLine("Kill Task");
}
}
}
The above thing runs fine but I have to loop the above DoWork task for every 3 minutes. Would it be a good thing to keep the above looping task in a timer that has an interval of 3 minutes? (In that way I would have to take care of Thread.Sleep x numberTrials not to exceed the Timer's interval). Any thoughts on this?
Have you also had a look at the Process.WaitForExit Method
It is explained with an example here: process restart loop
Related
I have a looper thread that is running always and pull tasks from queue in order to execute them.
There is a main looper method
public void Start()
{
m_looperThread = new Thread(() =>
{
while (true)
{
//Dequeue use lock inside
TASK_TYPE task = m_taskList.GetAndRemoveFirst();
if (task == null || !m_isThreadRunning)
{
break;
}
task.Execute();
FinishedTask(task);
}
}
)
{
IsBackground = true
};
m_looperThread.Start();
}
Now if I need to close an application, user need to click red cross and before closing I need to abort all looper tasks.
How I do it
public void Abort()
{
Put(default(TASK_TYPE));
m_isThreadRunning = false;
if (m_looperThread != null)
{
m_looperThread.Join();
}
m_taskList.Clear();
}
So, first of all I put a null item and additional I set m_isThreadRunning value to false because in looper method I am checking this values in order to stop it. Then I call .Join() to make sure that I finished this thread and clear task list. Now I know exactly that all tasks were aborted, threads were joined and all is fine.
But issue here in this line
task.Execute();
What is the issue - when task run and user need to close the application I can't .Join the looper thread before task finish the job (it could be 1 minute). And finally it is looks like application in stuck.
So, question is - how correctly .join the thread and give to user opportunity to close the application?
C# 3.5 Winforms app.
I have a timer that fires every 30 seconds on separate thread (all it does is write a string of text to the VS output window).
I also have another thread that waits for a certain process to end if it starts up. For example winword.exe.
In that thread I have this code:
p.WaitForExit();
And it will sit there and wait for winword.exe to exit. That works fine.
However, while it is sitting there waiting for winword.exe to exit, the 30 second timer on a completely separate thread (that sends text to the output window) never runs.
If I wait 3 minutes (so the other timer should of run 6 times at this point, but it does not while WaitForExit() is waiting), and then I exit winword.exe; all of sudden my other timer starts running 6 times at once. It is like there is a backlog of the timer event and all of a sudden .Net wants to run it all at the same time.
Why does p.WaitForExit() seem to block my whole application even though I have it executing from a separate thread in my app (not the main UI thread)?
Edit: Yes it is in a separate thread. Here is the code that I use to launch it:
try
{
Thread t = new Thread(ProcessCheck); // Kick off a new thread
t.Start();
ConfigLogger.Instance.LogInfo("++ ProcessCheck thread started # " + DateTime.Now);
}
catch (Exception ipwse)
{
ConfigLogger.Instance.LogInfo(ipwse.Message + " " + ipwse.StackTrace);
}
Here is the ProcessCheck() method that I have:
foreach (Process p in System.Diagnostics.Process.GetProcessesByName("winword"))
{
this.Invoke(new MethodInvoker(delegate()
{
try
{
p.WaitForExit();
}
catch (Exception)
{
}
}));
}
this.Invoke, if done from a WinForms form, will block the UI thread until the process has exited. If the Timer is System.Windows.Forms.Timer, the Tick event is raised on the UI thread. If the UI thread is blocked, that would explain why the Tick event is never raised.
I'm not sure because the following program shows that what you're doing works as long as you're doing the threading right.
static void Main(string[] args)
{
BackgroundWorker shortThread = new BackgroundWorker(), waitThread = new BackgroundWorker();
shortThread.WorkerSupportsCancellation = true;
shortThread.DoWork += (s, e) =>
{
while (true)
{
if (shortThread.CancellationPending)
{
break;
}
Console.WriteLine("Hello World...");
Thread.Sleep(2000);
}
};
waitThread.WorkerSupportsCancellation = true;
waitThread.DoWork += (s, e) => { Process.Start("winword.exe").WaitForExit(); };
shortThread.RunWorkerAsync();
waitThread.RunWorkerAsync();
Console.ReadLine();
shortThread.CancelAsync();
waitThread.CancelAsync();
}
So, it seems to me that you're issuing the WaitForExit() on the main thread instead of a separate thread.
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 kept a polling timer to check if a process is running or not. I have the following simple code for this:
bool alreadyChecked = false; //check if the wait to check the second time is already over
**Timer_elapsed event**
Process sampleProcess[] = Process.GetProcessesByName("notepad");
if(sampleProcess.length > 0)
{
//Process is running
return;
}
else
{
//Process is not running, so do the following
//Wait for some time and check again (set alreadyChecked = true when the wait is over)
if (alreadyChecked){
//Run the process}
else{
//The process has started running while we were waiting
return;}
}
I am not able to implement the waiting code inside the event, so that it can wait and then fire the event again. (Even if we implement the wait time, the Timer_elapsed event will be fired by timer again while we were waiting.)
Any suggestions?
You should create a separate thread and use the sleep method, using a BackgroundWorker is the best option. You can also use a timer thread.
**BackgroundWorker_DoWork event**
int nTrials = 0; // this method will help you pick any number of trials before launching the applicaion
bool isRunning = false;
while((isRunning = Process.GetProcessesByName("notepad") == 0) || nTrials < 2)
{
Thread.Sleep(1000); // w8 1 second before queriying the process name
nTrials++;
}
if ( isRunning ) RunProcess();
Don't use the sleep method on your main thread or your application will stop handling messages for the sleep time.
In an application I'm developing, I have a main form that simply sits there and displays log data, and a worker thread that autonomously does the work in a loop.
MyWorker worker = new MyWorker();
MainForm mainForm = new MainForm();
// Subscribe form to log event so log data gets displayed
worker.Log += mainForm.Log;
// Start the worker thread's MainLoop
new Thread(new ThreadStart(worker.MainLoop)).Start();
// Show the form (blocking)
Application.Run(mainForm);
// If we end up here, the form has been closed and the worker has to stop running
worker.Running = false;
As you can see, whenever the form is closed, the worker thread should be stopped. The worker looks like this:
public class MyWorker
{
public String Running { get; set; }
public MyWorker()
{
Running = true;
}
public void MainLoop()
{
while (Running)
{
DoExtensiveWork1();
if (!Running) return;
DoExtensiveWork2();
if (!Running) return;
DoExtensiveWork3();
if (!Running) return;
DoExtensiveWork4();
if (!Running) return;
DoExtensiveWork5();
if (!Running) return;
// We have to wait fifteen minutes (900 seconds)
// before another "run" can be processed
for (int i = 0; i < 900; i++)
{
Thread.Sleep(1000);
if (!Running) return;
}
}
}
}
As you can see, I want the thread to be able to stop when switching between successive work operations, but not when within an operation. When an operation (DoExtensiveWorkN) has finished, its status and results are persisted do disk or database, so quitting while an operation is in progress (by, for example, Thread.Abort) is not an option.
However, I find this code I've just written repulsive to look at, especially the "wait loop" which sleeps for one second 900 times, to prevent the thread from idling for 15 minutes before detecting Running has been set to false.
I'd rather be able to throw some kind of event to stop the main loop as soon as it's finished a piece of work.
Can anyone point me in the right direction how to do this, or if a total rewrite is required because I totally misunderstood threading, show me somewhere where those principles are explained?
You can tidy up both the running of the individual tasks and the 15 min wait loop considerably.
I'd suggest perhaps using something like this:
public class MyWorker
{
private readonly ManualResetEvent _stopEvent = new ManualResetEvent(false);
private readonly Action[] _workUnits;
private bool Running
{
get { return !_stopEvent.WaitOne(0); }
}
public MyWorker()
{
_workUnits = new Action[]
{
DoExtensiveWork1,
DoExtensiveWork2,
DoExtensiveWork3,
DoExtensiveWork4,
DoExtensiveWork5
};
}
public void Stop()
{
_stopEvent.Set();
}
public void MainLoop()
{
while (Running)
{
foreach (var workUnit in _workUnits)
{
workUnit();
if (!Running) return;
}
// We have to wait fifteen minutes (900 seconds)
// before another "run" can be processed
if (_stopEvent.WaitOne(900000)) return;
}
}
}
Then to stop the process at the next appropriate point:
Worker.Stop();
I would suggest using System.Timers.Timer.
You can do your work with the running thing and rather than using the sleep you can just set the timer to go off again in 15 minutes.
If you want to stop it early then call some kind of abort method (similar to setting your Running=true variable) that will stop the timer.
It should be noted that each time the timer event fires it will start up a new thread so you dont' need to worry about killing background threads. Your thread finishes its run of processing, sets the timer to run in 15 minutes and then the thread finishes naturally. If you abort during a wait then you just get rid of the timer and no more cleanup needed. If you abort during a run then you let the run finish and at the end it checks a flag and doesn't start the timer again and then the thread finishes.
For the timer you'll want to set the timer to start manually at the end of the process. The alternative is to have the timer ticking every 15 minutes but that would mean that if your processing took 10 minutes then it owuld only be 5 minutes before the next run. And if it took more than 15 minutes you may be in trouble. Also restarting the timer manually guarantees that the processing shouldn't restart while another is running.