1

I'm developing a c# application. I need 2 threads; the main one, and another that is continuously looking for information through my database. I want to use Dispatcher Timer as:

dispatcherBd.Tick += (s,e) => CallPoll (s,e);
dispatcherBd.Interval = new TimeSpan(0,0,0,100);
dispatcherBd.Start();

If i do this into my main thread, everything works perfectly, but if I do into a new thread. It doesn't work.

public Main(){
    threadDB = new Thread(InitDispatcher);
    threadDB.Start();
}

private void InitDispatcher(){
    DispatcherTimer dispatcherBd.Tick += (s,e) => CallPoll (s,e);
    dispatcherBd.Interval = new TimeSpan(0,0,0,100);
    dispatcherBd.Start();
}

What's the problem?

René Vogt
  • 43,056
  • 14
  • 77
  • 99
rosa.tarraga
  • 145
  • 1
  • 2
  • 10
  • use dispatcher.invoke on your timer's tick – Arphile Sep 02 '19 at 07:37
  • 1
    What do you mean "it doesn't work"? – Loocid Sep 02 '19 at 07:38
  • I mean that it is not executed every 100ms, just 1 time. – rosa.tarraga Sep 02 '19 at 07:42
  • 1
    The Timespan signature you are using is 100 seconds, not 100 milliseconds. Your first example shouldn't tick every 100ms either. [Docs](https://learn.microsoft.com/en-us/dotnet/api/system.timespan.-ctor?view=netframework-4.8#System_TimeSpan__ctor_System_Int32_System_Int32_System_Int32_System_Int32_) – Loocid Sep 02 '19 at 07:44
  • excuse me, i mean 100s – rosa.tarraga Sep 02 '19 at 07:44
  • 1
    Is `dispatcherBd` a local variable or a field? Just a guess: if it's a local variable it might get garbage collected and hence the timer is destroyed. – René Vogt Sep 02 '19 at 07:54
  • private void InitDispatcher(){ DispatcherTimer dispatcherBd = new DispatcherTimer(); dispatcherBd.Tick += (s,e) => CallPoll (s,e); dispatcherBd.Interval = new TimeSpan(0,0,0,100); dispatcherBd.Start(); } – rosa.tarraga Sep 02 '19 at 07:59
  • @r.t.moreno11 that's what I mean, make `dispatcherBd` a **field** or your class instead of a local variable, so it won't get garbage collected. – René Vogt Sep 02 '19 at 08:05
  • 1
    DispatcherTimer needs a dispatcher, your new thread doesn't have one. Use the right kind of timer class, either System.Timers.Timer or System.Threading.Timer gets the job done without you having to use a thread. If "CallPoll" takes less than 20 msec then just use DispatcherTimer on the main thread. – Hans Passant Sep 02 '19 at 09:57

2 Answers2

1

As you stated in the comments, you declare dispatcherBd as a local variable inside InitDispatcher():

private void InitDispatcher()
{
    DispatcherTimer dispatcherBd = new DispatcherTimer();
    // ...

So dispatcherBd is only in scope inside InitDispatcher and will be availabe for garbage collection as soon as the method is left.
When it gets garbage collected and finalized, the timer event will no longer be raised.

So try changing dispatcherBd to a field instead:

private DispatcherTimer dispatcherBd;

private void InitDispatcher()
{
    dispatcherBd = new DispatcherTimer();
    // ...

But note that DispatcherTimer invokes its handler on the UI thread. So if CallPoll takes a lot of time, your UI will be blocked.
So you might want to start another thread from the timer's handler:

dispatcherBd.Tick += (s, e) => { Task.Run(() => CallPoll(s, e)) };

or use a System.Threading.Timer instead of a DispatcherTimer. That one runs the Tick event on a thread pool thread.

In both cases you need to get back to the UI thread when you want to display the results on your UI.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
0

Forget about manual threading unless absolutely necessary. Use Task.Run as a way to schedule your (possible, continuous) job on another thread. Don't forget about Dispatcher.Invoke proxy if you need to update your UI from newly created (non-UI) thread.

In case things are getting too complicated, consider Reactive Extensions. There exists timer out of the box and many, many more.

Zazaeil
  • 3,900
  • 2
  • 14
  • 31