sleep-until in c#
Asked Answered
Q

4

6

I want to run a function periodically every 1 second, so after 10 seconds it is executed 10 times. The simplest approach is using a loop like this :

while(true)
{
Thread.Sleep(1000);
function();
}

But the main problem with this approach is that it will not provide any periodic guarantees. I mean if it takes 0.1 seconds to run function() the executions time of the function will be like this : 0, 1.1 , 2.2, 3.3, 4.4 , ...

As I remember, in real time language ADA we have a function sleep-until(#time). Now I'm looking for an alternative in C#.

Any sample code will be appreicated.

Quimper answered 11/10, 2012 at 7:48 Comment(9)
Sleep in smaller inverals and check if a whole second has passed before you execute your code.Clastic
What do you want to happen if function() takes more than 1 second to execute?Metaxylem
c# is not a real time language. its not even guarranted the thread will execute exactly after 1 second, as there might be other threads / processes. if you need to be that precise, maybe you should use some other tools?Otology
I assume it will not take longer than 1 sec.but if multi threading is possible I like to run them in parallel. I know c# is not a realtime language but interested to know if we can simulate realtime behaviour in some way.Quimper
#4410058Schrecklichkeit
@Quimper can you elaborate on what you're trying to achieve? threads real level of parallelism is limited to number of cores your pc has. anythign above this pays the price of OS's context switching. both the answers provided here so far wont really work the way you expect it, and you will always have some level of overhead and time wasted.Otology
why do you want to run the function every 1 second? Spawning a new thread every one second or queuing the task to thread pool will cause additional threads to be created. If the function can be run truly concurrently then you may want to utilize Task Parallel Library. The TPL will efficiently utilize the multi-core infrastructure.Delgado
@Otology Since c# is not designed to be a realtime language I think there is no other way to achieve what I'm looking for. Do you have any other suggestion ? @ jags I think my thread will finish job before the deadline, so I think there is no problem here.Quimper
@Quimper , i just dont think that its a big price to pay, in most of the cases. if its very important for you to be as precise as possible, probably using a smaller intervals is a better idea. as of using timer - it still wont be 100% precise..Otology
C
7
System.Threading.Timer timer = new System.Threading.Timer(ThreadFunc, null, 0, 1000);

private static void ThreadFunc(object state)
{
    //Do work in here.
}

See MSDN for more info.

Cadena answered 11/10, 2012 at 7:53 Comment(1)
I will do that after 2 minute (you can accept an answer after 2 minute)Quimper
L
2

You can use Stopwatch to measure the time. I would also use a For-Loop instead.

var sw = new System.Diagnostics.Stopwatch();
var timeForOne = TimeSpan.FromSeconds(1);
var count = 10;
for(int i = 0; i < count; i++)
{
    sw.Restart();
    function();
    sw.Stop();
    int rest = (timeForOne - sw.Elapsed).Milliseconds;
    if (rest > 0)
        System.Threading.Thread.Sleep(rest);
}
Lil answered 11/10, 2012 at 7:56 Comment(4)
Great, but I still think the last if block, the calculation of rest and sleep function call consume sometime and cannot see any advantages over the previous one !! It is an alternative but the other one looks simpler :)Quimper
@user1654052: Actually it is unquantifiable what TimeSpan.Subtract+ if (rest > 0) consumes, it is absolutely negligible and less than 1 millisecond.Lil
its not just that. take a look carefully.[ sw.stop ; int rest = blah ; if (rest>0) ] all executed without considering its time and task swiches :) I know it looks negligible but if it is going be run for one years you can not guarantee that the function is executed every one second. that is why I don't think it is an acceptable answerQuimper
@user1654052: You can omit the sw.Stop(); because it will be used only once later(sw.Elapsed). Anyway, all three lines will consume far less than a millisecond because they are simple arithmetic. However, you are right that you need compensation for rounding issues etc. if it's running for a long time and you need high precision.Lil
C
1

To invoke something after specific interval of time you should use Timer class. Here is the Tutorial

Coley answered 11/10, 2012 at 7:51 Comment(0)
M
0

If you use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive and add using System.Reactive.Linq; - then you can do this:

IDisposable subscription =
    Observable
        .Interval(TimeSpan.FromSeconds(1.0))
        .Subscribe(_ => function());

To stop the observable you just call subscription.Dispose();.

Merideth answered 31/3 at 2:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.