简体   繁体   中英

Windows 10 LTSB and C# Winforms - Threading Issue

So my issue here is simple. I've designed a WinForms application and it works well on my machine (Win7), and in fact other machines, yet when I run the application on a Windows 10 2016 LTSB machine, my background threads do not work as expected - yet some do perform as expected.

Application flow:

  • Wait 1 minute (obj1 with Threading.Timer)
  • Post event (a string message from obj1 when MainWindow calls obj1)
  • Update form text (with info from event message)
  • Perform operation (background thread)
  • Post event message (from background thread to MainWindow)
  • Wait random period (obj1 with Threading.Timer)
  • Post event (a string message from obj1)
  • Update form
  • Wait 1 minute

Now for some privacy policies/reasons I cannot share the exact things that operate here and how the classes are structured, but here is a rudimentary class structure:

class MainWindow
{
    List<Controller> controllers = new List<Controller>();
    List<ControllerDisplay> controllerDisplays = new List<ControllerDisplay>();
    Queue<string> requests = new Queue<string>();
    
    private void AppLifetimeLoopCallback(object state)
    {
        while (requests.Count > 0)
        {
            string request = requests.Dequeue();
            string response = controllers[i].ProcessRequest(request);
            string anotherResponse = controllerDisplays[i].ProcessResponse(response);
            if (!string.NullOrWhiteSpace(anotherResponse))
            {
                requests.Enqueue(anotherResponse);
            }
        }
        
        for (int i = 0; i < controllers.Count; i++)
        {
            requests.Enqueue("STATE?");
        }
        
        timer.Change(300, Threading.Timeout.Infinite);
    }
}

class Controller
{
    public string ProcessRequest(string request)
    {
        switch (request)
        {
            case "STATE?":
              if (shouldRequest)
              {
                  return "REQ:1234";
              }
              else if (isProcessing)
              {
                  return "PRQ:1234";
              }
              else
              {
                  return "IDLE";
              }
              
              break;

            case "APPROVE":
              shouldRequest = false;
              isProcessing = true;
              thread = new Threading.Thread(new ThreadStart(() =>
              {
                  Threading.Thread.Sleep(300);
                  isProcessing = false;
                  return "RQF:1234";
              })
              {
                  IsBackground = true,
              };
              thread.Start();
              
              break;

            case "DENY:
              shouldRequest = false;
              break;
        }
    }
}

class ControllerDisplay
{
    public string ProcessResponse(string response)
    {
        switch (request.Substring(0, 4))
        {
            case "REQ:":
              thread = new Threading.Thread(new ThreadStart(() => 
              {
                  // perform some checks
                  if (isValid)
                  {
                     return "APPROVE";
                  }
                  else
                  {
                      return "DENY";
                  }
              })
              {
                  IsBackground = true,
              };
              thread.Start();
              
              break;

            case "RQF:":
              thread = new Threading.Thread(new ThreadStart(() =>
              {
                  // finalize and cleanup request bits
                  return "APPROVE";
              })
              {
                  IsBackground = true,
              };
              thread.Start();
              
              break;

            case "PRQ:":
              // update UI
              break;
        }
    }
}

Now firstly, I know there seems to be some discrepancy between the millisecond delay in the code and the description of the flow - however note that there is another Thread in the Controller which toggles the shouldRequest value at this minute interval which switches up the response messages to perform the "request" when the device's state is requested.

Secondly I also have registered to the UnhandledException as well as the ThreadException events of the application which should log any undesired behaviour that occurred.

Third, note that in MainWindow there is a Threading.Timer (not in code - I know) that is updating the UI with the current date and time every second.

Now the issue here that I've noticed is that on the Win10LTSB2016 machine, the application stops performing the background operations. Some of the threads must have just died off or something as ie the date and time keeps updating as expected, but one controller will be stuck in request state and another in a request complete state - and no error messages logged / MessageBox . Note that the machine does not go into any sleep or hibernate state in this period that the threads just stop, and another note is that the memory sockets is 1, not 2 (as I read that this could affect the threads losing communication with each other if they are compartmentalized to different processor groups and your application is not written to handle this).

Closing off: Note that when I perform checks to see if I should ie start the request process thread in the Controller class so as to not do the same request over and over until state change is detected, I do the following:

lock (checkLock)
{
    if (isProcessingRequest)
    {
        break;
    }
    else
    {
        lock (resourceLock)
        {
            isProcessingRequest = true;
        }
    }
}

thread = new Threading.Thread(new ThreadStart(() =>
{
    lock (resourceLock)
    {
        // finalize and cleanup request bits
        isProcessingRequest = false;
    }
    
    return "APPROVE";
})
{
    IsBackground = true,
};
thread.Start();

I'm closing this question as it is complete hogwash and I apologize to those for the time they spent reading this.

So the manual locks on the Queue<T> kept causing a deadlock before, thus they were removed. Now it seemed to resolve the issue at first, but long running tests proved every now and again (what I thought was a Windows issue) a deadlock occurred.

The reason I had thought this was a Windows issue is because someone telling me that this is what they experienced on Windows and it is definitely a Windows issue. Not looking down on anyone, but he does not do threading as he does not know how and the mentioned result was from his attempt to do threading. Lesson learned here.

Thanks guys and/or gals.

EDIT: The issue was resolved and long running tests are looking very promising thus far. To achieve this, I simply changed Queue<T> to ConcurrentQueue<T> and a few modifications to code where needed (ie ConcurrentQueue<T>.Clear() does not exist where Queue<T>.Clear() does).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM