Seeing different behavior in Debug (with debugger attached) vs. Reese mode

I’m precalculating timing buffers for Signal Generator pins and executing them in non-blocking mode.

After all 3 buffers are precalculated, I create an instance of the “Controller” class and scheduling its “Run” method in the improvised “thread pool” that runs one thread at a time. When Run method executes, it execute 3 Signal Generators in non-blocking mode and waits until all 3 Signal Generators are finished using flowing code


            while (XStepPort.Active || YStepPort.Active || ZStepPort.Active)
            {
                // block untill all SignalGenerators finished toggling
            }

ISSUE:
It looks like that the SignalGenerator.Active does not work in Release mode, it returns false even if SignalGenerators still toggling. :wall:

Class code:


  internal class Controller
    {
        public SignalGenerator XStepPort { get; set; }
        public SignalGenerator YStepPort { get; set; }
        public SignalGenerator ZStepPort { get; set; }

        public OutputPort XDirPort { get; set; }
        public OutputPort YDirPort { get; set; }
        public OutputPort ZDirPort { get; set; }

        public uint[] XTimingBuffer { get; set; }
        public uint[] YTimingBuffer { get; set; }
        public uint[] ZTimingBuffer { get; set; }

        public bool XDirValue { get; set; }
        public bool YDirValue { get; set; }
        public bool ZDirValue { get; set; }

        public int Dwell { get; set; }

        public void Run()
        {
            // direction control
            if (XDirPort.Read() != XDirValue)
                XDirPort.Write(XDirValue);

            if (YDirPort.Read() != YDirValue)
                YDirPort.Write(YDirValue);

            if (ZDirPort.Read() != ZDirValue)
                ZDirPort.Write(ZDirValue);

            // movement control
            if (XTimingBuffer.Length > 0)
                XStepPort.Set(true, ZTimingBuffer);

            if (YTimingBuffer.Length > 0)
                YStepPort.Set(true, YTimingBuffer);

            if (ZTimingBuffer.Length > 0)
                ZStepPort.Set(true, ZTimingBuffer);

                // this seem to work only in Debug mode !
            while (XStepPort.Active || YStepPort.Active || ZStepPort.Active)
            {
                // block untill all SignalGenerators finished toggling
            }

            if (Dwell > 0)
                Thread.Sleep(Dwell);
        }
    }

Is this a defect?

Do you have a USB cable connected but no Debugger SW connected to the Controller?
The NETMF runs in to serious timeouts when trying to send debug info out. This also happens when you build in relese mode.
At least up to NETMF 4.3 you Need to have VS MFDeploy or FezConfig connected to the Controller when a USB cable is connected.

or there is a race condition which shows up in release mode. try a delay at the beginning of the program to allow for background initialialization.

I did have a USB connected. I’ll try to run disconnected.

But I don’t think the issue is related to it. As it works as expected in Debug mode with debugger attached. And don’t work as expected when application deployed and debugger is not attached. Works as expected means: It should not start new SignalGenerator thread until execution of the previous thread is complete as the following code should block the execution.

while (XStepPort.Active || YStepPort.Active || ZStepPort.Active)
{
// do nothing
}

No, not this time. The execution starts from the button click, not on startup.

@ EvoMotors -

What device are you using?
We tested simple code on G400 and no issue found.
Can you please provide complete example that we can reproduce?

Here is our test example:

static InputPort ldr1 = new InputPort((Cpu.Pin)(4), false, Port.ResistorMode.PullUp); 
        static OutputPort led1 = new OutputPort((Cpu.Pin)(3 * 32 + 3), false); 
        public static void Main()
        {
            while (ldr1.Read() == true)
            {

                Thread.Sleep(25);
                led1.Write(!led1.Read());
               

            }

            
            uint[] XTimingBuffer = new uint[1000];
            uint[] YTimingBuffer = new uint[1000];
            uint[] ZTimingBuffer = new uint[1000];
            var XStepPort = new SignalGenerator((Cpu.Pin)(0 * 32 + 27), true); 
            var YStepPort = new SignalGenerator((Cpu.Pin)(0 * 32 + 28), true); 
            var ZStepPort = new SignalGenerator((Cpu.Pin)(0 * 32 + 29), true); 
            int cnt = 0;
            XStepPort.Set(true, ZTimingBuffer);
            YStepPort.Set(true, ZTimingBuffer);
            ZStepPort.Set(true, ZTimingBuffer);
            while (XStepPort.Active || YStepPort.Active || ZStepPort.Active)
            {
                // block untill all SignalGenerators finished toggling
                Debug.Print("Blocking...." + cnt++);
            }
            Debug.Print("Done...." + cnt++);
            while (true)
            {
                Thread.Sleep(50);
                led1.Write(!led1.Read());
            }
        }

I’m using FEZ Cobra III
The complete example would be 40+ classes. I’ll have to create completely different project.

But try to remove “Debug.Print(“Blocking…” + cnt++);” from the while loop, I can’t do anything inside the loop as it takes too long, it is very important to me to return as soon as all 3 Signal Generators finish executing.

@ Dat -

In my app is more like in the code below (not the exact code but close enough)


    static class Program
    {
        public static void Main()
        {
            ThreadUtil.MaximumThreads = 1;

            for (int i = 0; i <= 5; i++)
            {
                Controller controller = new Controller
                {
                    XStepPort = new SignalGenerator((Cpu.Pin)(0 * 32 + 27), false),
                    YStepPort = new SignalGenerator((Cpu.Pin)(0 * 32 + 28), false),
                    ZStepPort = new SignalGenerator((Cpu.Pin)(0 * 32 + 29), false),
                    XTimingBuffer = new uint[1000],
                    YTimingBuffer = new uint[1000],
                    ZTimingBuffer = new uint[1000]
                };
                ThreadUtil.Queue(controller.Execulte);
            }
        }
    }

    internal class Controller
    {
        public SignalGenerator XStepPort { get; set; }
        public SignalGenerator YStepPort { get; set; }
        public SignalGenerator ZStepPort { get; set; }

        public OutputPort XDirPort { get; set; }
        public OutputPort YDirPort { get; set; }
        public OutputPort ZDirPort { get; set; }

        public uint[] XTimingBuffer { get; set; }
        public uint[] YTimingBuffer { get; set; }
        public uint[] ZTimingBuffer { get; set; }

        public bool XDirValue { get; set; }
        public bool YDirValue { get; set; }
        public bool ZDirValue { get; set; }

        public int Dwell { get; set; }

        public void Execulte()
        {

            // direction control
            if (XDirPort.Read() != XDirValue)
                XDirPort.Write(XDirValue);

            if (YDirPort.Read() != YDirValue)
                YDirPort.Write(YDirValue);

            if (ZDirPort.Read() != ZDirValue)
                ZDirPort.Write(ZDirValue);

            // movement control
            if (XTimingBuffer.Length > 0)
                XStepPort.Set(true, ZTimingBuffer);

            if (YTimingBuffer.Length > 0)
                YStepPort.Set(true, YTimingBuffer);

            if (ZTimingBuffer.Length > 0)
                ZStepPort.Set(true, ZTimingBuffer);

            while (XStepPort.Active || YStepPort.Active || ZStepPort.Active)
            {
                // block untill all SignalGenerators finished toggling
            }

            if (Dwell > 0)
                Thread.Sleep(Dwell);
        }
    }

    public static class ThreadUtil
    {
        /// <summary>
        /// Synchronizes thread queue actions
        /// </summary>
        private static readonly object lockObject = new object();

        /// <summary>
        /// List storing our available threadpool threads
        /// </summary>
        private static readonly ArrayList availableThreads = new ArrayList();

        /// <summary>
        /// Queue of actions for our threadpool
        /// </summary>
        private static readonly Queue threadActions = new Queue();

        /// <summary>
        /// Wait handle for us to synchronize de-queuing thread actions
        /// </summary>
        private static readonly ManualResetEvent threadSynch = new ManualResetEvent(false);

        /// <summary>
        /// Maximum size of our thread pool
        /// </summary>
        public static int MaximumThreads { get; set; }

        /// <summary>
        /// Starts a new thread with an action
        /// </summary>
        /// <param name="start"></param>
        public static void Start(ThreadStart start)
        {
            try
            {
                var t = new Thread(start);
                t.Start();
            }
            catch (Exception ex)
            {
                Debug.Print(ex.ToString());
            }
        }


        /// <summary>
        /// Queues an action into the threadpool
        /// </summary>
        /// <param name="start"></param>
        public static void Queue(ThreadStart start)
        {
            if (MaximumThreads == 0)
                MaximumThreads = 1;

            lock (lockObject)
            {
                threadActions.Enqueue(start);

                // if we haven't spun all the threads up, create a new one
                // and add it to our available threads
                if (availableThreads.Count < MaximumThreads)
                {
                    var t = new Thread(ActionConsumer);
                    availableThreads.Add(t);
                    t.Start();
                }

                // pulse all waiting threads
                threadSynch.Set();
            }
        }

        /// <summary>
        /// Indefinitely wait until an action is queued. When an action is de-queued safely execute it
        /// </summary>
        private static void ActionConsumer()
        {
            while (true)
            {
                // wait on action pulse
                threadSynch.WaitOne();

                ThreadStart action = null;

                // try and de-queue an action
                lock (lockObject)
                {
                    if (threadActions.Count > 0)
                        action = threadActions.Dequeue() as ThreadStart;
                    else
                        // Safely reset the mutex so that everyone waits until the next action is queued
                        threadSynch.Reset();
                }

                // if we got an action execute it
                if (action != null)
                {
                    try
                    {
                        action();
                    }
                    catch (Exception ex)
                    {
                        Debug.Print("Error in thread pool: " + ex);
                    }
                }
            }
        }
    }

Stupid question, but what Visual Studio version are you using? I couldn’t get anything running reliable in VS2015, with VS2013 theres no problem. That begins with the debugger that can’t be attached and ends with the execution of my application just stops after some time or it doesn’t startup completly at all (on a G120 and a G400). When I use VS2013 there are no issues at all.

For me it’s completely opposite, the issue stats when its running without VS :smiley:

For me there are issues depending on the VS-version that deployed the project to the device, no mater if it’s connected past that point or not.

@ EvoMotors -

Please try my simple code above to see what happen. I don’t think problem is SignalGenerator.

Yes, USB cable connected but no Debugger attached = extremly slow execution = a lot of trouble

Did this ever get fixed? I installed GHI Electronics NETMF SDK 2016 R1 on a new PC and updated the firmware on a Cobra II to use it. If I am not actively debugging or I run a release version of the code, it executes VERY slowly. If I plug the Cobra II into a USB power supply (as opposed to a computer) it runs just fine (debug or release). Since this was working fine before (a year or so ago) with the old FW (don’t recall the exact version, but for sure this worked fine on NETMF v4.2) it seems like this is a FW issue, though it could also be a NETMF 4.3 issue.

I have a workaround (don’t do that :)) but it seems like this is a bug that should be addressed at some point. Are other people still seeing it? Do you need more information to figure out what is really wrong?

It’s not necessarily a bug in the firmware. When you attach the debugger, the context-switching behavior of your code changes, because the debugger support code in the interpreter is active. There will be more context switching or just different timing in your code due to debugger ‘noise’ and this can unblock deadlocks and improve perceived performance when what you really have is a bug in your threading or resource management (locks/mutexes) code.

If performance decreases when you detach the debugger, it can either be a known issue with Debug.Print (which should go away in Release builds) or a bug in your thread management (which will not go away in Release code).

Thanks for the quick response. The culprit was:

It seems that even in Release mode Debug.GC() will attempt to send stuff using Debug.Print() so the issue can't be resolved with using Release code.

So, any idea if/when the well known issue with Debug.Print() will be fixed?  I can work around the issue, by remembering it is there, but it would be nice to not have to do so.  I use Debug.GC() to get an idea of how much memory is leaking (and fix it, if it is).