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.
Related
I want to run a process every one minute, but I have been told that the Timer is working every x minute + the time required for the process to finish. but I want the thread to work every 1 minute even though the thread process may keep working for 1 hour.
I hope you got me, so in the final image, I may have 10 threads working together.
is that possible ?
Depends on the timer. Simple test shows that System.Threading.Timer works the way you want:
var timer = new Timer(s => { "Start".Dump(); Thread.Sleep(10000); "Hi!".Dump(); },
null, 1000, 1000);
Thread.Sleep(20000);
timer.Dump();
The callback executes every second even though it takes ten seconds to execute.
This is basically because the callback for this particular timer is simply posted to the threadpool, while e.g. System.Windows.Forms.Timer is actually tied to the UI thread. Of course, if you simply start a new thread (or queue work, or start a new task etc.) in the callback of winforms timer, it will work in a similar (albeit less precise) way.
Using the right tool for the job usually makes things much easier :)
Create a Timer and on the elapse event just fire a new thread to do the work, like the below example:
public class Example
{
private static Timer aTimer;
public static void Main()
{
// Create a timer with a two second interval.
aTimer = new Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program... ");
Console.ReadLine();
Console.WriteLine("Terminating the application...");
}
public static void DoWork()
{
var workCounter = 0;
while (workCounter < 100)
{
Console.WriteLine("Alpha.Beta is running in its own thread." + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
workCounter++;
}
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
// Create the thread object, passing in the method
// via a delegate.
var oThread = new Thread(DoWork);
// Start the thread
oThread.Start();
}
}
Since .NET 4.0 Tasks are preferred to Threads.
The overhead of Task management is minimal.
// Create a task spawning a working task every 1000 msec
var t = Task.Run(async delegate
{
while (isRunning)
{
await Task.Delay(1000);
Task.Run(() =>
{
//your work
};
}
});
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.
How can I restrict timer thread execution time? I have long running timer work that should work no more than 30 seconds.
The only way to do this is to have a second thread (possibly the one that created the worker thread) monitor and then kill it or gracefully call it to quit immediately. Killing threads you should avoid, and only use as the last resort. Here is example how:
Thread t = new Thread(myLongThreadProc);
t.Start();
Thread.Sleep(30000);
t.Abort();
By 'gracefully call it to quit', I mean to set some stop variable to some value, and give the thread some short time to quit itself, otherwise you kill it. But it is the design of your thread function to make it actually quit. Here is the sample code:
Thread t = new Thread(myLongThreadProc);
threadRun = true;
t.Start();
Thread.Sleep(30000);
threadRun = false; //this variable is monitored by thread
if (!t.Join(1000)) //inside your thread, make sure it does quit in one second
{ //when this variable is set to false
t.Abort();
}
And should I mention that your caller thread does not have to sleep for 30 seconds, but you can use a timer instead (if it is a form thread) or do something useful and check periodically - or have a third worker thread just counting 30 seconds...
Just have your worker method start a 30-second timer and check to see if it's elapsed as your worker does its thing:
bool timerElapsed;
public void DoWork()
{
timerElapsed=false;
System.Timers.Timer timer = new System.Timers.Timer(30000);
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
while (true)
{
if (timerElapsed)
{
// handle 30-sec elasped error
break;
}
// continue doing work and break when done
}
timer.Stop();
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timerElapsed = true;
}
In my app, I have a thread that runs continuously. By using Thread.Sleep(), the function executes every 10 minutes.
I need to be able to kill this thread when a user clicks a button. I know Thread.Abort() is not reliable. I can use a variable to stop the thread, but since it is sleeping it could be another 10 minutes before the thread kills itself.
Any ideas?
Why don't you use a timer to schedule the task every ten minutes instead. That will run your code on a thread pool thread and thus you will not have to manage this yourself.
For more details see the System.Threading.Timer class.
Instead of Thread.Sleep use a System.Threading.ManualResetEvent. The WaitOne method has a timeout just like Thread.Sleep, your thread will sleep for that interval unless the event is triggered first, and the return value tells you whether the interval elapsed or the event was set.
So here's a sample that users timers to do the work as suggested by Brian. Use start/stop as needed. To cleanup the (Program) object once you are done with it make sure you call Dispose.
Just note that when you call Stop it will prevent the timer from firing again, however you still may have a worker thread in the middle of executing the timer_Elapsed handler, i.e. stopping the timer doesn't stop any currently executing worker thread.
using System;
using System.Timers;
namespace TimerApp
{
class Program : IDisposable
{
private Timer timer;
public Program()
{
this.timer = new Timer();
this.timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
this.timer.AutoReset = true;
this.timer.Interval = TimeSpan.FromMinutes(10).TotalMilliseconds;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
// TODO...your periodic processing, executed in a worker thread.
}
static void Main(string[] args)
{
// TODO...your app logic.
}
public void Start()
{
this.timer.Start();
}
public void Stop()
{
this.timer.Stop();
}
public void Dispose()
{
this.timer.Dispose();
}
}
}
Building on Ben's answer, here's the pattern to help you out...
using System.Threading;
public class MyWorker {
private ManualResetEvent mResetEvent = new ManualResetEvent(false);
private volatile bool mIsAlive;
private const int mTimeout = 6000000;
public void Start()
{
if (mIsAlive == false)
{
mIsAlive = true;
Thread thread = new Thread(new ThreadStart(RunThread));
thread.Start();
}
}
public void Stop()
{
mIsAlive = false;
mResetEvent.Set();
}
public void RunThread()
{
while(mIsAlive)
{
//Reset the event -we may be restarting the thread.
mResetEvent.Reset();
DoWork();
//The thread will block on this until either the timeout
//expires or the reset event is signaled.
if (mResetEvent.WaitOne(mTimeout))
{
mIsAlive = false; // Exit the loop.
}
}
}
public void DoWork()
{
//...
} }
One possibility is to not have it sleep for ten minutes. Have it sleep for 10 seconds then only do its work on every sixtieth wakeup. Then you only have a latency of ten seconds before it stops.
Aside: This is not necessarily the best solution but it's probably the quickest to implement. As with all possibilities you should do a cost/benefit analysis when selecting which solution is right for you.
If ten seconds is still too much, you can drop it further although keep in mind that dropping it too far will result in a possible performance impact.
You're right that you shouldn't kill threads from outside, it's usually a recipe for disaster if you happen to do it while they have a lock on some resource that's not freed on kill. Threads should always be responsible for their own resources, including their lifetimes.
I want to call a Business layer method from a Windows service (done using C# and .NET) after every 10 seconds. However, i dont want to use the Timer_Elapsed event since it starts up another thread/process if the first thread/process is still running. I just need a single threaded approach, since multiple calls to the same Business method creates unwanted complications.
So i added a do--while loop in the on_start. I know this is not the correct way since it spawns this process which becomes an orphan if the service is shut down.
How can i approach this problem ?
Regards,
Chak
There's another way to get timed execution, the WaitHandle.WaitOne() method provides a timeout argument. That works very nicely in a service as it lets you implement the need to stop the service and periodic execution in a single method call. The template looks like this:
Thread Worker;
AutoResetEvent StopRequest = new AutoResetEvent(false);
protected override void OnStart(string[] args) {
// Start the worker thread
Worker = new Thread(DoWork);
Worker.Start();
}
protected override void OnStop() {
// Signal worker to stop and wait until it does
StopRequest.Set();
Worker.Join();
}
private void DoWork(object arg) {
// Worker thread loop
for (;;) {
// Run this code once every 10 seconds or stop right away if the service
// is stopped
if (StopRequest.WaitOne(10000)) return;
// Do work...
//...
}
}
Use a timer, but as soon as you enter the Timer handler method, disable the timer so that no more events are raised. Just before exiting the handler, re-enable the timer.
Check out this discussion, and in particular the answer by jsw. It suggests a synchronization mechanism to prevent multiple simultaneous calls to the business logic. Just disabling the timer in the Elapsed handler method isn't guaranteed to prevent parallel calls since the handler is invoked on a separate thread. Use a lock as jsw suggests, and stop the timer within the synchronized code block.
Alternatively, you could use a Timer and set the AutoReset property to false. That way, the Elapsed event is raised only once and you can reset the timer manually towards the end of the handler method.
while(true)
{
..do something
Thread.sleep( some time or day);
}
Thread thread;
private void DoWork(object arg)
{
while (true)
{
// Run this code once every 20 seconds or stop if the service is stopped
try
{
Thread.Sleep(20000);
//Do work....
}
catch(ThreadInterruptedException)
{
return;
}
}
}
protected override void OnStart(string[] args)
{
// Start the thread
thread = new Thread(DoWork);
mWorker.Start();
}
protected override void OnStop()
{
// interrupt thread and wait until it does
thread.Interrupt();
thread.Join();
}