WiFiRS9110 and multi-threading

Hello,

I am trying to use my WiFi RS9110 board with FEZ Cobra II. It works fine when I initialize the board in the main process thread. But as soon as I move the initialization logic into a thread (to do all the work in the background), I get HardwareTimeoutException. My board is updated to the latest firmware available. Has anyone seen this kind of a behavior? Is it ‘forbidden’ to initialize the WiFi from a separate thread?

Thanks,
Vigen

Please provide a minimal example code demonstrating the issue.

Do you have any Thread.Sleep’s in your thread? I’ve seen strange errors when a thread locks the whole system.

Does thread.sleep(0) allow a thread to give an opportunity for another thread to run? Does this mean all my threads should have a thread.sleep(0)?

thread.sleep(20) is a good idea - but a better idea is to use an appropriate delay that is suitable for your code/application. if you use (0) it at least causes a context switch so it will give up the processor if another thread needs time.

All threads should at some point yield with a sleep or you will deadlock as NETMF is not pre-emptive. Used 0 if your thread needs to run faster. 20ms for example is approx 20 characters on a 9600 bps serial port.

I’ve compiled a simple code snippet for the forum, and it appeared to work just fine. So, it seems I have some sort of a dead lock in my code which results in hardware timeouts.


public static void Main()
{
    WiFiRS9110 wifiInterface = new WiFiRS9110(SPI.SPI_module.SPI2, G120.P1_17, G120.P2_21, G120.P1_14);

    Thread thread = new Thread(() =>
    {
        try
        {
            ConnectWiFi(wifiInterface);
        }
        catch (Exception e)
        {
            Debug.Print("Exception: " + e.ToString());
        }
    });
    thread.Start();

    // do other initializations

    // avoid the program to exit
    while (true)
    {
        Thread.Sleep(1000);
    }
}

public static void ConnectWiFi(WiFiRS9110 wifiInterface)
{
    string SSID = "myssid";
    string Password = "mypassword";
    int TimeoutMilliseconds = 60 * 1000;

    Debug.Print("Opening the interface");
    wifiInterface.Open();
    wifiInterface.EnableDynamicDns();
    wifiInterface.EnableDhcp();

    Debug.Print("Scanning for SSID " + SSID);
    wifiInterface.OperationTimeout = TimeoutMilliseconds;
    WiFiRS9110.NetworkParameters[] netparams = wifiInterface.Scan(SSID);
    if (netparams.Length > 0)
    {
        Debug.Print("Joing the network");
        netparams[0].Key = Password;
        wifiInterface.Join(netparams[0]);
        while (wifiInterface.IPAddress == "0.0.0.0")
        {
            Debug.Print("Acquiring network address...");
            Thread.Sleep(500);
        }
        Debug.Print("Address is " + wifiInterface.IPAddress);
    }
}

After thourough inspection, I’ve found a simple sample that results in the HardwareTimeoutException. Surprisingly, it is caused by the TimerCallback. The following snippet will block WiFiRS9110.Open call until the TimerCallback action exits. Here are the related call stacks (I don’t know how to get more detailed call stack information for NETMF runs):

WiFiRS9110 thread:[em]
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext)
[Managed to Native Transition]
GHI.Networking.dll!GHI.Networking.WiFiRS9110.WaitOn(System.Threading.AutoResetEvent waiter) + 0xa bytes
GHI.Networking.dll!GHI.Networking.WiFiRS9110.RunFirmware() + 0x32 bytes
GHI.Networking.dll!GHI.Networking.WiFiRS9110.OnOpening() + 0x6 bytes
GHI.Networking.dll!GHI.Networking.BaseInterface.Open() + 0x3b bytes
[/em]

TimerCallback thread:[em]
mscorlib.dll!System.Threading.Thread.Sleep(int millisecondsTimeout)
[Managed to Native Transition]
My.exe!MyClass.Main.AnonymousMethod__1b(object obj) Line 190 + 0x13 bytes C#
[/em]


public static void Main()
{
    WiFiRS9110 wifiInterface = new WiFiRS9110(SPI.SPI_module.SPI2, G120.P1_17, G120.P2_21, G120.P1_14);

    Thread thread = new Thread(() =>
    {
        try
        {
            ConnectWiFi(wifiInterface);
        }
        catch (Exception e)
        {
            Debug.Print("Exception: " + e.ToString());
        }
    });
    thread.Start();

    // This will block WiFiRS9110 APIs
    Timer timer = new Timer(new TimerCallback((obj) =>
    {
        Debug.Print("Timer called");
        Thread.Sleep(25000);
        Debug.Print("Timer called ended");
    }), null, 0, 24 * 60 * 60 * 1000);

    // avoid the program to exit
    while (true)
    {
        Thread.Sleep(1000);
    }
}

public static void ConnectWiFi(WiFiRS9110 wifiInterface)
{
    string SSID = "myssid";
    string Password = "mypassword";
    int TimeoutMilliseconds = 60 * 1000;

    Debug.Print("Opening the interface");
    wifiInterface.Open();
    wifiInterface.EnableDynamicDns();
    wifiInterface.EnableDhcp();

    Debug.Print("Scanning for SSID " + SSID);
    wifiInterface.OperationTimeout = TimeoutMilliseconds;
    WiFiRS9110.NetworkParameters[] netparams = wifiInterface.Scan(SSID);
    if (netparams.Length > 0)
    {
        Debug.Print("Joing the network");
        netparams[0].Key = Password;
        wifiInterface.Join(netparams[0]);
        while (wifiInterface.IPAddress == "0.0.0.0")
        {
            Debug.Print("Acquiring network address...");
            Thread.Sleep(500);
        }
        Debug.Print("Address is " + wifiInterface.IPAddress);
    }
}

@ vigen1980 - you are blocking the event thread of the framework in the timer handler. this is not good practice. Funny/undesirable things can happen.

you should minimize the amount of processing done in system event handlers. If a lot of processing is required, using a technique like the producer/consumer pattern.

Mike, I was not aware that the system event processing is single threaded, but guessed it was the case with the Timer experiment. The PubSub will obviously solve the issue here, but it sort of takes me back to the Symbian OS times where all the processing should have been single-threaded and take as little time as possible.

What are good multi-threading practices on G120 board? Is there a limit on the amount of threads that badly degrades the performance due to context switching? I just don’t want to do PubSub as it reduces the readability and future maintainability of the code :slight_smile: