Problemen met threads

Bij het werken met de widgettoolkit is het belangrijk om het onderliggende threadmodel te kennen dat wordt gebruikt voor het lezen en verzenden van platformevents. De implementatie van de interfacethread is van invloed op de regels die toepassingen moeten volgen als er Java-threads in hun code zijn opgenomen.

Standaard ingebouwde eventmeldingen

Het platform detecteert interface-events onder het gebruikersinterfaceniveau van de toepassing en plaatst deze in toepassingseventwachtrijen, ongeacht de taal of interfacetoolkit. Hoewel de werking voor besturingssystemen onderling enigszins verschilt, zijn de basisprincipes gelijk. Als de gebruiker op de muisknop klikt, lettertekens typt of vensters opent, genereert het besturingssysteem toepassingsinterface-events, bijvoorbeeld muisklikken, toetsaanslagen en opvulacties. Hierdoor wordt bepaald welke vensters en toepassingen de events moeten ontvangen. De events worden in de eventwachtrij van de toepassing geplaatst.

De onderliggende structuur in venstergebaseerde toepassingen is een eventlus. Toepassingen initialiseren en starten een lus die de gebruikersinterface-events in de wachtrij leest en erop reageert. Werk dat tijdens het afhandelen van een van deze events wordt gedaan, moet snel gebeuren om het mogelijk te maken dat de interface op de gebruiker reageert.

Landurige bewerkingen die door interface-events worden geïnitieerd, moeten worden uitgevoerd in een afzonderlijke thread om te zorgen dat de eventlusthread snel de resultaten retourneert en de volgende event ophaalt uit de wachtrij van de toepassing. Toegang tot de widgets en platform-API vanuit andere threads moet met expliciete vergrendeling en serialisering worden beheerd. Als een toepassing die zich niet aan de regels houdt, kan een aanroep van het besturingssysteem misgaan of kan de gehele gebruikersinterface vastlopen.

SWT-interfacethread

SWT volgt het threadmodel dat direct door de platforms wordt ondersteund. De toepassing voert de eventlus uit in de hoofdthread en meldt events rechtstreeks vanuit deze thread. De gebruikersinterfacethread is de thread waarin de Display is gemaakt. Alle andere widgets moeten in de interfacethread worden gemaakt.

Omdat de gehele eventcode wordt geïnitieerd vanuit de interfacethread van de toepassing, heeft toepassingscode die events afhandelt vrije toegang tot de widgets en kan zonder speciale technieken grafische afbeeldingen aanroepen. De toepassing draagt echter zorg voor het vertakken van berekeningsthreads bij het uitvoeren van lange bewerkingen als reactie op een event.

Opmerking: De SWT initieert een SWTException voor aanroepen vanuit een niet-interfacethread die vanuit een interfacethread gedaan moeten worden.

De hoofdthread van een SWT-toepassing heeft, inclusief de eventlus, de volgende structuur:

   public static void main (String [] args) {
      Display display = new Display ();
      Shell shell = new Shell (display);
      shell.open ();
      // Eventlus starten. Wordt gestopt als de gebruiker
      // het venster sluit.
      while (!shell.isDisposed ()) {
         if (!display.readAndDispatch ())
            display.sleep ();
      }
      display.dispose ();
   }

Als de widgets zijn gemaakt en de shell geopend is, leest en meldt de toepassing de events in de systeemwachtrij tot het shellvenster wordt gesloten. Als er geen events beschikbaar zijn in de wachtrij, wordt de display op non-actief gezet, zodat er andere toepassingen uitgevoerd kunnen worden.

De SWT biedt speciale toegangsmethoden om widgetcode en code voor grafische elementen vanuit een achtergrondthread aan te roepen.

Code uitvoeren via een thread die niet van de gebruikersinterface is

Toepassingen die gebruikersinterfacecode willen aanroepen vanuit een niet-interfacethread, moeten hiervoor een Runnable gebruiken. De methoden syncExec(Runnable) en asyncExec(Runnable) in de klasse Display worden gebruikt om deze runnables in de interfacethread uit te voeren tijdens de eventlus.

In het volgende codefragment ziet u het model voor het gebruik van deze methoden:

   // Tijdsintensieve berekeningen
   ...
   // Nu gebruikersinterfcae bijwerken. Verdere bewerkingen zijn
   // niet afhankelijk van het resultaat, dus asynchroon.
   display.asyncExec (new Runnable () {
      public void run () {
         if (!myWindow.isDisposed())
            myWindow.redraw ();
      }
   });
   // Meer berekeningen
   ...

Het is een goede gewoonte om te controleren of uw widget uit de runnable wordt verwijderd als u asyncExec gebruikt. Omdat er tussen het aanroepen van asyncExec en het uitvoeren van de runnable andere dingen kunnen gebeuren in een interfacethread, is het nooit zeker welke status de widgets hebben als de runnable wordt uitgevoerd.

De workbench en threads

De regels voor threads zijn duidelijk als u een SWT-toepassing vanaf het begin implementeert, omdat u het maken van de eventlus en het vertakken van berekeningsthreads in de toepassing zelf in de hand hebt.

Het wordt moeilijker als u plugincode voor de workbench aanlevert. U kunt de volgende regels beschouwen als "afspraken" voor het gebruik van interfaceklassen voor het platform. Per release kunnen er uitzonderingen op de regel zijn: