Main Site Documentation

More Timer confusion


#1

Here’s a simple NETMF project running on a FEZ Cerberus (in full):

using System.Threading;
using Microsoft.SPOT;

namespace TimersWTF1
{
    public class Program
    {
        public static void Main()
        {
            Debug.Print("Startup memory: " + Debug.GC(true));
            Thread.Sleep(2000);
            new Program().Run();
        }

        public Program()
        {
            Debug.Print("Progam initializing");
            //
            var timer = new Gadgeteer.Timer(100);
            timer.Tick += Tick;
            timer.Start();
            //
            var afterInitMemory = Debug.GC(true).ToString();
            Debug.Print("After init memory: " + afterInitMemory);
        }

        private void Tick(Gadgeteer.Timer timer)
        {
            Debug.Print("Tick");
        }

        public void Run()
        {
            while (true)
            {
                Debug.Print("Memory: " + Debug.GC(true));
                Thread.Sleep(5000);
            }
        }
    }
}

The output I would expect to see in the debug output is the “Memory: XX” reports from within the Run method’s “while (true)” loop interspersed with “Tick” from the timer. Instead this is what happens:

[quote]Startup memory: 84588
Progam initializing
After init memory: 83136
Memory: 83124
Memory: 81324
Memory: 74004
Memory: 65868
Memory: 59268
Memory: 52668
Memory: 42996
Memory: 36396
Memory: 29796
Memory: 23196
Memory: 16596
Failed allocation for 1026 blocks, 12312 bytes
A first chance exception of type ‘System.OutOfMemoryException’ occurred in mscorlib.dll[/quote]

I’ve tried various values in the Thread.Sleep: 100, 1,000, and 5,000 and in each case the Timer.Tick never visibly fires and eventually the Cerb crashes with a System.OutOfMemoryException.

Why is this running out of memory?


#2

(N.B. swapping the timer so that it is an instance variable not a local variable has no effect.)


#3

I’d still be interested to know what the problem was, but I’m going to abandon Gadgeteer.Timer in my NETMF projects in favour of ExtendedTimer as the following code works as expected.

using System.Threading;
using Microsoft.SPOT;

namespace TimersWTF1
{
    public class Program
    {
        private ExtendedTimer _Timer;
        public static void Main()
        {
            Debug.Print("Startup memory: " + Debug.GC(true));
            Thread.Sleep(2000);
            new Program().Run();
        }
        public Program()
        {
            Debug.Print("Progam initializing");
            _Timer = new ExtendedTimer(Tick, null, 0, 100);
            Debug.Print("After init memory: " + Debug.GC(true));
        }

        private void Tick(object timer)
        {
            Debug.Print("Tick");
        }

        public void Run()
        {
            while (true)
            {
                Debug.Print("Memory: " + Debug.GC(true));
                Thread.Sleep(5000);
            }
        }
    }
}

#4

I don’t need ExtendedTimer, it’ll work with Timer (thanks Justin), so the message I’m taking is to not use Gadgeteer.Timer in vanilla NETMF


#5

I think I know what is going on here. I have debugged your code and I think the following thing is happening: Tick method is never called because you first call Run method which enter endless loop and you are on the same thread. Tick events add up until you run out of memory.


#6

Does Gadgeteer.Timer use the same thread - I thought not? Looking at the Gadgeteer source (https://gadgeteer.codeplex.com/SourceControl/latest#Main/GadgeteerCore/Gadgeteer42/Timer.cs ) it uses Microsoft.SPOT.DispatcherTimer and so I would expect it to use a different thread, no?


#7
Namespace GadgeteerApp1
    Partial Public Class Program
        Dim WithEvents t As New Gadgeteer.Timer(1000)

        Public Sub ProgramStarted()
            t.Start()
            For i = 1 To 20
                Thread.Sleep(1000)
            Next
            Debug.Print("20 seconds have elapsed. You will see ticks only now.")
        End Sub

        Private Sub s_Tick(timer As Gadgeteer.Timer) Handles t.Tick
            Debug.Print("tick")
        End Sub
    End Class
End Namespace

This test case shows that timer runs on the same thread. You won’t see “tick” printed for the first 20 seconds, after that you will get 20 “tick” printed instantly (events were building up) and then you will see “tick” printed every next second.


#8

It “must” or it “runs”? Have you tried my sample code?

Timer starts DispatcherTimer. From Expert .NET Micro Framework book: "dispatcher timers are fully integrated in the dispatcher’s queue, and they do not create an extra thread when started.


#9

You are right about the behavior on the DispatcherTimer. It runs on the same thread but, what or who is adding up ticks if the thread remains locked on the endless loop?? The dispatcher is locked the thread itself remains locked on the loop so nothing can execute a single byte of instruction on the thread. I believe that the GC is yet locked and even the calls to Debug.GC plus the Thread.Sleep are consuming some extra bytes that at the end and without spare time for the thread to make its house keeping and dispatcher frame processing, ends up with the raised System.OutOfMemoryException!


#10

This scenario is another reason why, without understanding the internals, you would not want to mix the Gadgeteer components outside a Gadgeteer application. Without the proper initialisation of the Gadgeteer framework, I can see why the Gadgeteer.Timer isn’t working in Netmf.


#11

I hear you Brett! But when working on a project that uses the same chip as the Cerb and includes several components (accelerometer, N18 display, …) that have Gadgeteer modules then it is tempting to raid the Gadgeteer code for projects to reference. I can see I’ll need to be more careful with that approach.