The timer runs in a different wire than the one that created it

advertisements

Using Visual Studio 2015, visual C# windows application.

I need a timer that empties a queue in the main thread because some UI components are modified. I coded this:

    public Form1()
    {
        InitializeComponent();
        Q = new ConcurrentQueue<amsg>();
        timer = new System.Timers.Timer(100);
        timer.Elapsed += timer_Elapsed;
        timer.Enabled = true;
    }

    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        clsUdpMsg msg;
        while (Q.TryDequeue(out msg)) handleRx(msg);
    }

but the Elapsed event executes in a worker thread...?

If I put a timer on the main form at design time the generated prototype is slightly different:

    private void timer1_Tick(object sender, EventArgs e)
    {
        amsg msg;
        while (Q.TryDequeue(out msg)) handleRx(msg);
    }

but this one DOES execute in the main thread context.

The question extends to any thread that creates a timer this way; I thought a timer created in a thread executes the elapsed event in the same thread context. Am I missing something?

Quick edit: I see where these are different timers, System.Timers.Timer and Windows.Forms.Timer. So - how do I reliably create timers that will execute in the thread where I create them?


Yeah, you're just dealing with two separate Timer classes. System.Windows.Forms.Timer fires its Tick event on the main thread and System.Timers.Timer fires its Elapsed event on a background thread. The advantage of System.Windows.Forms.Timer is that it hides the threading; the advantage of System.Timers.Timer is that it doesn't require a message pump to work.

You ask, "How do I reliably create timers that will execute in the thread where I create them?" Well, this is easy when you have a Windows Forms GUI and are starting the Timer on the UI thread: just use System.Windows.Forms.Timer. If you don't have a message pump to take advantage of, you have to use a System.Timers.Timer and basically the only way to run something on the main thread when the timer fires its Elapsed event is to recreate something like a message loop in your main thread--have it sit, maybe waiting for a Monitor.Pulse or some other kind of notification from the timer thread. But this means your main thread won't be getting anything useful done in the meantime...