Windows Forms Controls Using Multiple Threads
In reworking Display Application of my exploratory project with its generalization in mind, I found myself in the Windows multithreading quagmire once again.
This is because in "emulating" the protocol of the ARINC-661 (A661) aerospace standard my Visual C# based Display Application is connected to multiple Ada User Applications. For A661, each separate user application communicates with a separate "layer" of the display surface as interacted with via the Display Application. Each user app, display app connection is via a separate communications channel.
The Display Application transmits widget event messages to the user application associated with the display layer. In response, the user application transmits to the display a command to manipulate the display – such as whether to hide one widget and show another, add text to a list box, display a new form and the like. That is, the Display Application doesn't contain its own logic to modify the state of the display but passes that task along to the User Application associated with the layer.
Therefore, my Visual C# application is not a normal application of Visual Basic, C#, etc. The forms and the widgets to be displayed within them are not supplied using the Visual language's features. Instead a definition file is supplied to define what the forms and their widgets are, where they are to be displayed, etc as well as the "super" forms that are the layers that can contain multiple forms. The user application of the layer commands when to display a particular form and which widgets of the form are to be displayed.
Because of this, the communications for a layer must wait upon the receive of the next command message. Therefore, each layer has to have a receive thread that can block while waiting for a message from its user application.
This, in turn, causes the entry into the Windows multithreading swamp since Windows can't handle (directly) commands to modify a form from a thread other than the one that created it. See, for instance, "How to: Make Thread-Safe Calls to Windows Forms Controls" of Visual Studio 2010 of the Microsoft web site. [msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx] See the Community Content comments as well.
In my own case, I have created different display threads for each display layer and a Windows timer for the layer. Then, when a command is received for a particular layer, I add it to a queue for that layer. When the Windows timer for a layer trips, the elapsed timer handler then checks whether the associated queue has any entries. If so, it calls a common display function to interpret the queued command. That function will be executing in the particular display thread so when it uses Windows display functions for a widget (form or control) it will be executing in the thread that Windows expects.
One gotcha is that the Windows timer handler (as opposed to a system timer) is only entered when both the timer has elapsed and the thread is running. That is, the application has to have the correct display thread running before the timer can be created that supplies the name of the unique handler. Therefore, the thread has to be created and running to display the form (forms of the layer in the case of the exploratory project) while also creating the particular Windows timer within the thread. This establishes the thread to be used for particular forms and controls (widgets) and the timer to elapse that is to be used to read the command queue.
No comments:
Post a Comment