C# timer while function is running - c#

I have a function (call it Process()) that does some processing. I want to call it at a point and at the same time start a timer. Then I want to call the next statement after the function only if 100 seconds have elapsed (and of course the function has finished). I don't want to sleep for 100 seconds as sleep suggests that the processor is just waiting - I want the processing function to be running while the timer is ticking.
I'm not sure what I should use. Some say use a task. Any suggestions?

int Ticks = Environment.TickCount;
ReallyBigFunction();
if(Environment.TickCount - Ticks > 100*1000)
{
// The function took more than 100 seconds
}

I'd suggest spinning the function off on another thread, then sleep for 100 seconds on your main thread. When your main thread wakes up again you can check whether or not the function thread has completed and join it back into the main program flow.

If you still want the process to be running, you may want to start a new thread that will wait the time you need:
ThreadStart start = delegate()
{
Thread.Sleep(100000);
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action(ThreadDoSomething)); //The function who will execute what you want to do.
};
new Thread(start).Start();
Note : The current code will give you access to the interface.

Related

System.Threading.Timer ... Time of next fire?

I have a question about the timer. Does interval time count time of callback executions? I mean for example - I have a timer set to fire every 15 seconds and it executes a callback function that lasts approximately 3 seconds in time. When the next time the timer will fire? In 18 seconds (after callback completes) or after 15 seconds (without waiting for callback)???
Thanks in advance
It will fire every 15 seconds regardless of the callback execution time. If you want it to include the callback execution time, you can suspend and restart the timer in the callback as follows;
At the start:
someTimer.Change(Timeout.Infinite, Timeout.Infinite)
.. and at the end, change it back with the same method:
someTimer.Change(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15))
It will fire every 15 secs. Any delays by the callback do not affect the timer. The callback executes on a separate ThreadPool thread. From the docs
The method does not execute on the thread that created the timer; it executes on a ThreadPool thread supplied by the system.
If you want to take the processing time into account, you would have to manage the timer yourself - start a single-fire timer and reset it from inside the callback, eg:
TimerCallback tcb = MyCallBack;
//Start the timer once after 15 secs
_timer=new Timer(tcb,null,TimeSpan.FromSeconds(15),TimeSpan.Infinite);
...
void MyCallBack(Object stateInfo)
{
....
//Reset the timer
_timer.Change(TimeSpan.FromSeconds(15),TimeSpan.Infinite);
}
An easier and cleaner way is to use async/await to wait X seconds after each asynchronous execution. For example, the following code will execute a method 15 secs after its last execution:
while(...)
{
await Task.Delay(TimeSpan.FromSeconds(15));
var response=await Task.Run(()=>someMethod());
...
}
or, if you want to execute code that is already asynchronous
while(...)
{
await Task.Delay(TimeSpan.FromSeconds(15));
await myHttpClient.GetStringAsync(someURL);
}
Under the hood, Task.Delay creates a single-fire timer and completes when the timer finishes. It's almost the same thing you would do manually.

Timer delegate call says "The memory could not be read"

So here's the thing i have a function and a timer that has an interval of 10ms.
void process()
{
//some heavy processing logic here
}
Now what i'm doing is that i have added this function to the timer.tick delegeate
timer1.tick += process;
When I run my program I'm getting exception that says
Multiple threads started to execute the same block and 'The instruction at some address referenced to another address.The memory could not be read'
But when I increase the interval time to 500ms, this exception is thrown after some time.
I am kind of new to c#, Is there any other efficient way of doing this without facing such an error.
You starting process every timer tick, so after a while your pc will really slow down. It is because you do not control thread numbers.Moreover I assume that they are using same resources, because you do not pass any arguments. This resources are probably not thread safe and this causes an exception
timers tick trigger after interval finish. your function in use by multiple ruinning Context . change timer interval as long as max run of your Process method and change to this ( disable timer in start function and enable after that ):
void process()
{
timer1.Enabled=false;
//some heavy processing
timer1.Enabled=true;
}
otherwise you must use semaphores.
Now i realized that in this function i had some variables that were being used by the program to run correctly , so when this function was being accessed many a times by different threads at the same time , it malfunctioned.
So i prevented this by using locks
void process()
{
lock(frameExtractor) // frame extractor is the variable where frames are stored
// then do some heavy processing
}

Method calls from threads with a specific delay

I need to synchronize a method call, so that threads can call this method after a 500ms sleep. I have 10 threads that may run at the same time, so that simply introducing Thread.Sleep(500) does not help. How can I achieve this in the simplest way? What can you suggest?
_pool = new Semaphore(0, 10);
_pool.Release(10);
...
pool.WaitOne();
Thread thr = new Thread(WorkerThread);
t.Start(param);
...
public static void WorkerThread(object parameterData)
{
...
MethodToBeSynced();
...
_pool.Release();
}
If you know the number of concurrent threads (And given they start approx. the same time), you could use a Barrier with a PostPhaseAction delegate.
var barrier = new Barrier(10, (x) => Thread.Sleep(500));
The barrier waits until 10 threads are at a certain code point and once that happens, each thread will sleep for 500 ms and then continues.
If the exact number of threads is unknown, you could specify a wait timeout to not block infinite.
// Waits up until N threads are at the barrier or after the timeout has elapsed.
_barrier.SignalAndWait(500);
Use System.Threading.Timer
You can give it a callback function as well as the interval when to call this function.

How to estimate method execution time?

I have requirement to cancel method execution if it takes the more than two seconds to complete and restart it on another thread.
So, is there any way/call back mechanism/HACK, I can make method inform me that it crossed 2 seconds time limit?
check if network drive exists with timeout in c#
https://web.archive.org/web/20140222210133/http://kossovsky.net/index.php/2009/07/csharp-how-to-limit-method-execution-time
Async Pattern:
public static T SafeLimex<T>(Func<T> F, int Timeout, out bool Completed)
{
var iar = F.BeginInvoke(null, new object());
if (iar.AsyncWaitHandle.WaitOne(Timeout))
{
Completed = true;
return F.EndInvoke(iar);
}
F.EndInvoke(iar); //not calling EndInvoke will result in a memory leak
Completed = false;
return default(T);
}
You should create System.Threading.Timer on two seconds, and run your method in another thread and wait for callback from it, if method completes before timer runs you should dispose timer, otherwise you should abort thread in which you method are executing. This is pretty simple for example
using (new Timer(BreakFunction, true, TimeSpan.FromMinutes(2), Timeout.Infinite))
{
//TODO:here you should create another thread that will run your method
}
In BreakFunction you should abort thread that runs your methods
It would be good if you can find it. I've been looking for it too.
What I usually do is start the method in another Thread, and start a Timer with 2 seconds in this case. The first time it raises the event, just do:
if (a.IsAlive)
{
a.Abort();
}
Two important things:
The Thread declared should be visible by the method that handles the timer
When calling Abort(), it raises ThreadAbortException, so you should correctly handle it in the method.

Windows Service with AutoResetEvent

I'm currently building a Windows Service which needs to process a queue of messages that are sat in a database table. This queue could vary in length and could take anything from 5 seconds to 55 seconds to execute against all rows in the database (I'm currently using a test data set of 500,000 records)
The Windows Service is configured to run on a 30 second timer so I have tried, unsuccessfully, to ensure that when the timer delegate runs that it is not able to run again until the previous request to the method has completed successfully
I have the following code in my Windows Service OnStart method:
AutoResetEvent autoEvent = new AutoResetEvent(false);
TimerCallback timerDelegate = new TimerCallback(MessageQueue.ProcessQueue);
Timer stateTimer = new Timer(timerDelegate, autoEvent, 1000, Settings.Default.TimerInterval); // TimerInterval is 30000
autoEvent.WaitOne();
And the following code in MessageQueue.ProcessMessage:
Trace.Write("Starting ProcessQueue");
SmtpClient smtp = new SmtpClient("winprev-01");
AutoResetEvent autoEvent = (AutoResetEvent)stateObject;
foreach (MessageQueue message in AllUnprocessed)
{
switch (message.MessageType)
{
case MessageType.PlainText:
case MessageType.HTML:
SendEmail(smtp, message);
break;
case MessageType.SMS:
SendSms(message);
break;
default:
break;
}
}
autoEvent.Set();
Trace.Write("Ending ProcessQueue");
I'm using DebugView to analyse the view the Trace statements as the Service runs and I can see multiple instances of "Starting ProcessQueue" which occur every 30 seconds which is what I am trying to avoid happening
In summary: I want to call ProcessQueue and ensure that it is not executed again unless it has completed its work (this enables me to prevent the same messages in the queue being processed multiple times
I'm sure I'm missing something pretty obvious here so any help would be much appreciated :)
Dave
Why don't you have your delegate disable the timer and then re-enable it (or continue working, if timer would expire immediately) once it's through working. Provided the latency between timer firing and your delegate waking up is < 30 seconds, this should be watertight.
while (true)
{
Trace.Write("Starting ProcessQueue")
stateTimer.Enabled = false;
DateTime start = DateTime.Now;
// do the work
// check if timer should be restarted, and for how long
TimeSpan workTime = DateTime.Now - start;
double seconds = workTime.TotalSeconds;
if (seconds > 30)
{
// do the work again
continue;
}
else
{
// Restart timer to pop at the appropriate time from now
stateTimer.Interval = 30 - seconds;
stateTimer.Enabled = true;
break;
}
}
Your ProcessMessage is never checking if the resetEvent is signaled - it's just running regardless.
I post here how to fix this. However, this is not the ideal method to do what you want to do. See the bottom of my answer for that.
You have your call to autoEvent.WaitOne() in the wrong place; it should be at the beginning of the ProcessMessage method.
AutoResetEvent autoEvent = (AutoResetEvent)stateObject;
autoEvent.WaitOne();
Trace.Write("Starting ProcessQueue");
SmtpClient smtp = new SmtpClient("winprev-01");
foreach (MessageQueue message in AllUnprocessed){
You should also use the overload that accepts a time out value (int or timespan), and returns a bool If the method returns true, that means it was signaled, so you can continue. If it times out (because another iteration is still running), you should just return and not try to run the code again.
If you do not use such an overload, what you are doing would be no different than wrapping the ProcessMessage method's code in a critical section (lock() on a global var, for instance) - additional threads would block, and then needlessly run.
AutoResetEvent autoEvent = (AutoResetEvent)stateObject;
//wait just one ms to see if it gets signaled; returns false if not
if(autoEvent.WaitOne(1)){
Trace.Write("Starting ProcessQueue");
SmtpClient smtp = new SmtpClient("winprev-01");
foreach (MessageQueue message in AllUnprocessed){
Note that actually, a *ResetEvent isn't ideal here. You really just want to check if an instance is already running, and abort if so. ResetEvents aren't really made for that... but I wanted to address the question of using the ResetEvent anyway.
What would probably work better is to simply shut down the timer when the callback is called, and then restart it up when you are done. That way, it's impossible for that code to be re-entered while it's still running.
You absolutely would need to wrap all the code in the callback method in a try / finally though, so that you always restart the timer after.
You can trivially solve this by using a System.Threading.Timer. You make it a one-shot timer by setting its period to zero. Restart the timer in the callback. Overlapped execution of the callback is now impossible.
Since you run this so frequently, a different approach is to use a thread instead. You'll need an AutoResetEvent to signal the thread to stop in the OnStop() method. Its WaitOne() method gives you a free timer when you use the overload that takes the millisecondsTimeout argument.
Btw: note that the autoEvent.WaitOne() call in OnStart() is troublesome. It may timeout the service controller if the first email takes a long time to send. Just omit it, you got the timer started == service started.
I think you are making this a lot harder than it needs to be. Why not just create a separate thread that spins around an infinite loop calling MessageQueue.ProcessQueue and then waiting a certain amount of time before calling it again. If it is all happening on a single thread there is no way for anything to happen in parallel.
public class YourService : ServiceBase
{
private ManualResetEvent m_Stop = new ManualResetEvent(false);
protected override void OnStart(string[] args)
{
new Thread(Run).Start();
}
protected override void OnStop()
{
m_Stop.Set();
}
private void Run()
{
while (!m_Stop.WaitOne(TimeSpan.FromSeconds(30))
{
MessageQueue.ProcessMessage();
}
}
}
OnStart method
AutoResetEvent autoEvent = new AutoResetEvent(true);
while (true)
{
autoEvent.WaitOne();
Thread t = new Thread(MessageQueue.ProcessMessage);
t.Start(autoEvent);
}
What you want is a synchronization timer object. In Win32 this is known as a waitable timer (unfortunately some P/invoke is required, unless I'm mistaken).
Here's what you would do:
Create waitable timer (make sure it's auto-reset).
Set waitable timer with a period of 30 seconds.
Loop:
WaitForSingleObject(waitable timer) with infinite timeout.
Process queue.
If the processing takes more than 30s, the timer will simply remain set until you call WaitForSingleObject on it. Additionally, if the processing takes 20s for example, the timer will be signaled after 10 more seconds.

Categories

Resources