Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Simple" C# Time Thread Appears to be Freezing

I've been staring at this thread for some time and I believe my mind has shut down on it. Thinking that the best thing to do, in order to update the time in a UI TextBox, would be to create what I thought would be a simple thread to get the time and post it back to the UI control. After having fought with it for a while, I'm getting frustrated and thinking that I might just add the time in some other way. In the intrepid spirit of the adventurer, I'm giving it another go.

I've got a similar thread operating elsewhere in the app that takes a list and populates a DataGridView in a TabControl. I'd have thought that the process would be roughly the same, but I'm missing a key part. The entirety of the thread is below:

private void displayTime()
    {
        while (true)
        {
            String time;
            String date;

            time = DateTime.Now.TimeOfDay.ToString();
            int len = time.IndexOf('.');
            time = time.Substring(0, len);
            date = DateTime.Now.Date.ToString();
            len = date.IndexOf(' ');
            date = date.Substring(0, len);

            updateClock(time, date);
        }
    }
private void updateClock(String time, String date)
    {
        if (InvokeRequired)
        {
            BeginInvoke(new timeDel(updateClock), new object[] {time, date});
            return;
        }           

        ctrlTimeTxt.Text = time + "\n" + date;
    }

The above thread has been started in various places(in an attempt to debug), but is currently in the Form's Shown event handler. The Form begins to appear, but then everything seems to hang. When I place a breakpoint in the thread, I can step ad infinitum, but the UI never seems to get control back. What am I missing? I'll be happy to expand upon any neglected details.

Edit: A clarification: This thread is being started in a function that is handling the Shown event. The description of the Shown event is given as: Occurs whenever the Form is first shown. I think that might eliminate the theory that the UI thread is Invoking too quickly.

like image 355
Rich Hoffman Avatar asked Dec 22 '22 22:12

Rich Hoffman


2 Answers

The problem is that your while loop here is generating so many events that the event queue gets flooded:

while (true)
{
    // ...
    updateClock(time, date);
}

Instead of doing this in a thread you can use a Timer to generate events at a regular interval and do one step of your method for each event. This will also mean that you don't have to use Invoke as the timer generates events on the main thread.

There are also two other errors in your code:

  • Occasionally TimeOfDay.ToString() could output a time that hits exactly at a second change, in which case the result of ToString() will not be "12:23:34.00000" but just "12:23:34" which will cause your method to throw an exception.
  • You are calling DateTime.Now twice, but the value could have changed in between the two calls. Normally this won't matter but as it passes midnight it could show '23:59:99.999' but the day shows as the next day. It's probably not a significant error in this application but you ought to get into the habit of only calling DateTime.Now once when you want consistent values for the date and time.

To fix these errors and to simplify your code:

  • Add a timer to your form.
  • Set the timer's Enabled property to true in the designer.
  • Add this event handler to the Tick event:

    private void timer_Tick(object sender, EventArgs e)
    {
        DateTime now = DateTime.Now;
        textBox1.Text = now.ToString("HH:mm:ss\nyyyy-MM-dd");
    }
    

You may wish to adjust the format string depending on your needs.

like image 146
Mark Byers Avatar answered Jan 06 '23 08:01

Mark Byers


It doesn't surprise me that this isn't going well -- you're stuffing invokes in the UI thread message queue (with your BeginInvoke()) as fast as you can generate them. You may want to put a break (i.e. with System.Threading.Thread.Sleep()) in your displayTime() thread to give the UI thread time to do some work.

like image 38
twon33 Avatar answered Jan 06 '23 08:01

twon33