2

I am starting a timer and I want the method to wait until some time passed. I have searched in other similar questions but cannot find a clear answer. Why is does the following code freeze the app? elapsed time starts at 0 and intervall is 1000 (1sec)

private void timer2_Tick(object sender, EventArgs e)
    {
        elapsedtime2++;
    }

//this is inside my method
timer2.Start();
while (elapsedtime2 < 3)
    {

    }
timer2.Stop();
Mr Funk
  • 31
  • 2
  • 3
    You don't have any locking around the access to `elapsedTime2`, and yet it's read/written by multiple threads. The runtime is perfectly within its rights to remove the reads of `elapsedtime2` in the `elapsedtime2 < 2` check, which means your loop turns into an infinite one – canton7 Feb 11 '21 at 10:25
  • (+1) Thank you for this comment. I am trying to learn and this is the constructive criticisime i was looking for. Now I know what is going wrong. I will be looking into access locking and when/how/why reads can be removed at runtime. – Mr Funk Feb 11 '21 at 10:53
  • @canton7 can you give a reference or something? I had no clue that the runtime could do such thing: `remove the reads`. – rytisk Feb 11 '21 at 11:20
  • 1
    @rytisk I don't have one to hand, but it's a common feature of many languages that the compiler/runtime (and even the CPU) is allowed to reorder reads/writes such that the effects of the reordering aren't visible to the *current thread*. This is e.g. why `volatile` exists in C. In .NET, it's the JIT which does this, although not as much as some other languages. – canton7 Feb 11 '21 at 11:25
  • 2
    @rytisk: See for example this answer: https://stackoverflow.com/a/41634395/8248570 Quote: "The C# compiler and CLR jitter are permitted to make a great many optimizations that assume that the current thread is the only thread running." – SomeBody Feb 11 '21 at 12:05

2 Answers2

1

The easiest way to pause execution for a second is:

Thread.Sleep(1000);

If you're familiar with async/await, the async equivalent is:

await Task.Delay(1000);
canton7
  • 37,633
  • 3
  • 64
  • 77
  • `Thread.Sleep()` this worked well. Are there any restrictions to this method though? Any situations I should not use these. – Mr Funk Feb 11 '21 at 10:52
  • It's normal indicative of some other problem, but there's nothing wrong with it in itself. Of course your thread becomes unresponsive during this time, so if it's a UI thread for example, your UI is going to freeze – canton7 Feb 11 '21 at 10:54
  • I would mention `Task.Delay` before than `Thread.Sleep`, since it would probably be better suited if writing a UI, as seem to be the case here. – JonasH Feb 11 '21 at 12:27
  • @JonasH I don't see any mention that this is a UI application? If OP hasn't had a proper introduction to async/await, throwing it at them won't be helpful. Since they don't know about Thread.Sleep I was assuming that they probably wouldn't be familiar with async/await – canton7 Feb 11 '21 at 13:15
0

You can use events to get the desired behaviour:

private int elapsedtime2 = 0;
private ManualResetEventSlim mre = new ManualResetEventSlim();

private void timer2_Tick(object sender, EventArgs e)
    {
        elapsedtime2++;
        if(elapsedtime2 >= 3)
        {
            mre.Set();
        }
    }

If your elapsed time variable has the expected value, you can set the event.

mre.Reset();
timer2.Start();
mre.Wait();
timer2.Stop();

Before you start the timer, you unset the event. After you started your timer, you wait until the event is set.

SomeBody
  • 7,515
  • 2
  • 17
  • 33