0

I've been stress testing my C# Windows Forms and WPF programs together with "HeavyLoad". HeavyLoad is an application to stress test your PC in order to check if things keep running reliably. Which isn't the case with my program.

What I'm seeing is that whenever I run HeavyLoad, using all available cores, my program starts to lose events. This also happens with the following simple code:

XAML:

<Window x:Class="MultithreadedWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MultithreadedWPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <TextBox Text="{Binding MyText, UpdateSourceTrigger=PropertyChanged}"></TextBox>
    </StackPanel>
</Window>

Code behind:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _myText = string.Empty;
    /// <summary>
    /// This property is bound to a text box in my user interface.
    /// </summary>
    public string MyText
    {
        get { return _myText; }
        set
        {
            _myText = value;

            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("MyText"));
        }
    }

    public MainWindow()
    {
        InitializeComponent();

        //Create a timer to fire every second.
        Timer timer = new Timer(1000);
        timer.AutoReset = true;
        timer.Elapsed += Timer_Elapsed;
        timer.Start();

        DataContext = this;
    }

    /// <summary>
    /// The timer's previously elapsed time.
    /// </summary>
    DateTime previous = DateTime.Now;

    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //Save the current date and time.
        DateTime now = DateTime.Now;

        //Set the text accordingly.
        MyText = $"{now.ToString("HH:mm:ss")}, delta: {now - previous}";

        //Save the current time to calculate the next delta.
        previous = now;
    }
}

This happens in Windows Forms as well as WPF.


What I am seeing:

- When running without HeavyLoad:

  1. If my program is focused: the delta is around 1 second.
  2. If my program isn't focused: the delta is around 1 second.

- When running HeavyLoad:

  1. If my program is focused: the delta is somewhere between 1-3 seconds.
  2. If my program isn't focused: the delta is somewhere between 3-15 seconds.

This means not only is the user interface not updating, the event in the code behind isn't running or getting lost. Otherwise the delta would always be around 1 second.


The question:

EDIT: I was using the System.Timers.Timer in my example. Not a DispatcherTimer. After switching to a timeapi.h timer (AccurateTimer), I notice that events are delayed instead of missed.

I am using timers as an example. In my other programs the same issues occur with events received from TCP clients. In the real-life scenario's I am getting the same issues without running HeavyLoad, perhaps through Windows Update or other processes. We try to minimize the other processes as much as possible. There are no other programs (except for Windows services and such) running during the execution of our program.

Is there a way around this issue? Perhaps by forcing our program to not run on a certain core? Using a different Windows version (e.g. LTSC, IoT or whatever)?

Putting my program in a higher (or highest) priority does not seem to have enough of an effect.

  • Are they really _missed_ or just _delayed_ ? Windows isn't a real-time OS after all. – Fildor Oct 15 '19 at 14:45
  • You're asking for *real-time behavior* from a desktop application. Are you sure? Windows *can* handle soft-real-time workloads *using the proper programming techniques*. A timer on a background thread isn't the proper technique - if anythink, you'd need to *elevate* the thread priority, not reduce it – Panagiotis Kanavos Oct 15 '19 at 14:45
  • Are you aware of the event is called from a non-gui thread? `Timer` – Jeroen van Langen Oct 15 '19 at 14:46
  • _" I need my program to be never miss any event, not even during high CPU loads."_ Too bad. This always happens on a non-deterministic system. – Jeroen van Langen Oct 15 '19 at 14:48
  • Uh, It will never miss an event, the timer will be inaccurate. – Jeroen van Langen Oct 15 '19 at 14:48
  • 1. Who's listenting on the `PropertyChangedEvent`? 2. Don't run CPU intensive methods in the GUI thread. – Sani Huttunen Oct 15 '19 at 14:50
  • Even if the *timer* always fires, the *GUI thread* may not be active. If the system is under such heavy load that the UI takes more than 1 second to get updated, you won't see any events for that 1 second. Use a *different* mechanism to determine whether the events arrived, eg a ConcurrentQueue of timestamps, or simply checking whether the interval between timer events is too big. Update the UI only when there's something interesting to post, eg a long delay, and even then, post something that won't be lost in the next event. Post eg the count of delayed timestamps – Panagiotis Kanavos Oct 15 '19 at 14:52
  • 1
    In any case, .NET has no real-time guarantees. The GC can run at any time and cause significant delays. Multimedia workloads on Windows which *do* have time-sensitive requirements use the [Multimedia Class Scheduler Service](https://learn.microsoft.com/en-us/windows/win32/procthread/multimedia-class-scheduler-service?redirectedfrom=MSDN) through C and C++ – Panagiotis Kanavos Oct 15 '19 at 14:59
  • @PanagiotisKanavos I've realised that same thing after I posted my question and added a ConcurrentQueue in which I store a DateTime.Now in the Timer.Elapsed event. I print all values of the ConcurrentQueue in a separate thread. In these prints I see the same gaps as I am seeing in the delta time. – SoConfused Oct 15 '19 at 16:26
  • @SaniSinghHuttunen The UI listens to the PropertyChangedEvent through binding. I am not running any CPU intensive methods in the GUI thread, I am only printing the current DateTime. – SoConfused Oct 15 '19 at 16:35
  • What timer are you using? If `DispatcherTimer` (or the Winforms equivalent), it's based on the native WM_TIMER message, which is a **synthesized** message. I.e. it's only delivered when there's nothing left in the queue. If you are flooding the thread's message queue with other messages, it is perfectly expected and reasonable for timer events to be delayed or missed altogether. – Peter Duniho Oct 15 '19 at 19:31
  • Marked duplicate includes information on the unreliability of `DispatcherTimer`. See also https://stackoverflow.com/questions/14354561/how-to-make-dispatchertimer-events-smoother-in-wpf – Peter Duniho Oct 15 '19 at 19:36
  • @PeterDuniho I am not using the DispatcherTimer. I was using the System.Timers.Timer. I switched to a timeapi.h timer (AccurateTimer) and noticed that events aren't getting lost, but are getting delayed and then come in all at once. I will update my question taking this into account. – SoConfused Oct 16 '19 at 08:21
  • 1
    @Fildor After switching to a different timer for my example, I've noticed the events are delayed. Not missed. This is still far from the desired effect, though. – SoConfused Oct 16 '19 at 09:29

0 Answers0