Threads unexpectedly block when not attached to a debugger

I have found that threads created in static contexts, at least when called from the program entry point, are blocked by those created in a class when run in non-debug mode but seem to operate just fine when debugging. Here’s the code and output:

Program.cs:


using System;
using System.IO;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.IO;
using Microsoft.SPOT.IO;

namespace FEZ_Cobra_Console_Application1
{
    public class Program
    {
        public static void Main()
        {
            new TestClass();
            while (true)
            {
                for (int i = 0; i < 10000; i++)
                    ;
                Debug.Print("2");
            }
        }
    }
}

TestClass.cs:


using System;
using Microsoft.SPOT;
using System.Threading;

namespace FEZ_Cobra_Console_Application1
{
    class TestClass
    {
        public TestClass()
        {
            Thread Thread1;

            Thread1 = new Thread(TestMethod1);
            Thread1.Start();

        }

        private void TestMethod1()
        {
            while (true)
            {
                for (int i = 0; i < 100000; i++)
                    ;
                Debug.Print("1");
            }

        }
    }
}

Output in Debug:
2
2
2
2
2
2
2
2
2
2
1
2
2
2
2
2
2
2
2
2
2
1
2
2
2
2
2
2
2
2
2
2
2
1
2
2

Output not in debug:
2
1
1
1
1
1
1
1
1
1
1
1
1

Then if I change Program.cs to this:


using System;
using System.IO;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.IO;
using Microsoft.SPOT.IO;

namespace FEZ_Cobra_Console_Application1
{
    public class Program
    {
        public static void Main()
        {
            new Thread(() =>
                {
                    while (true)
                    {
                        for (int i = 0; i < 10000; i++)
                            ;
                        Debug.Print("3");
                    }
                }).Start();
            new TestClass();
            while (true)
            {
                for (int i = 0; i < 10000; i++)
                    ;
                Debug.Print("2");
            }
        }
    }
}

The outputs are,
Debug:
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
3
2
2
3
1
2
3
2
3
2
3
2

non-debug:
2
3
3
3
3
3
3
3
3
3
1
3
3
3
3
3
3
3
3
3
3
1
3
3
3
3
3
3
3

In my experimentation if the blocking thread returns the blocked thread starts executing. I think this is linked to static contexts as I ran across this behavior when creating singleton instances in the program entry point by calling static getters that instantiate non-static objects which create threads. I haven’t done a lot of experimentation to pin it on this for sure though.

Thanks

Try this with no debug:


using System;
using System.IO;
using System.Threading;
 
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
 
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.IO;
using Microsoft.SPOT.IO;
 
namespace FEZ_Cobra_Console_Application1
{
    public class Program
    {
        public static void Main()
        {
            TestClass t = new TestClass();
            while (true)
            {
                for (int i = 0; i < 10000; i++)
                    ;
                Debug.Print("2");
            }
            Debug.Print(t);
        }
    }
}

you are exiting your main function, which should not happen.

try putting a Thread.Sleep(Timeout.Infinite); after your while loops in main.

Well, it doesn’t exit since there is a while (true).
I guess the problem is that the reference is not kept for the created object (that contains the Thread) so the GC collects it when no debugging. When debugging, GC collection policy differs.

But the original poster did not have a while(true)…

I also believe that there is a bug in MF 4.1, which occurs when a thread is in a loop and does not release the CPU, that prevents GC from being automatically invoked.

Mike,

[quote]you are exiting your main function, which should not happen.
[/quote]
I don’t think I’m exiting the main function as godFather89 said there is a while(true), but why is exiting the main function a problem?
godFather89,
I tried your suggestion and I don’t find any difference. Also I think you meant “Debug.Print(t.ToString());” that statement is unreachable as well so hopefully it wouldn’t change anything, not that that has ever stopped a compiler before though ;)…

The last statement was just a trick to tell the compiler to keep the reference since it can tell if you use or not, so that the GC won’t collect the object.

I think if you insert some Thread.Sleep(0) statements into the loops you might get what you want. It is generally not a good idea to have a loop within a thread that never releases the CPU.

You can also try changing your TestClass to this:

using System;
using Microsoft.SPOT;
using System.Threading;
 
namespace FEZ_Cobra_Console_Application1
{
    class TestClass
    {
        private Thread Thread1 = null; // this has been moved
        public TestClass()
        {
            
 
            Thread1 = new Thread(TestMethod1);
            Thread1.Start();
 
        }
 
        private void TestMethod1()
        {
            while (true)
            {
                for (int i = 0; i < 100000; i++)
                    ;
                Debug.Print("1");
            }
 
        }
    }
}

Mike,
Changing the scope of Thread1 didn’t change anything, however adding a Thread.Sleep(0) as you suggest did, so when the loops look something like this:


                for (int i = 0; i < 10000; i++)
                    Thread.Sleep(0);

Things run as you’d expect. Perhaps the debugger is masking a context switching bug in the thread scheduler? Aside from synchronization I don’t think that one user mode thread should be able to indefinitely block another from executing, even if it’s a higher priority.

Wait for MF 4.2 and see if that works better for you.

KyleG, I am having a similar issue - see here http://www.tinyclr.com/forum/topic?id=9709

I was wondering if you ever managed to get to the bottom of this?

Thanks,
Michael.

This post is 9 months ago, but regarding to the code, I agree with MIke when he says that looping a while-true in the main method is not efficient !
If the problem you have in the 9709 post ID is the same, just try to initiate all your needed threads in the main, and do a Thread.Sleep(Timeout.Infinite) at the end of you main, which is very different than to do a loop while, in tems of processor instructions !