BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Actualités Le modèle de threading de Windows Runtime - 2ème partie

Le modèle de threading de Windows Runtime - 2ème partie

Cette deuxième partie d'article sur le threading dans Windows Runtime aborde les mécanismes internes du modèle. Cette section, présentée à l'origine par Marytn Lovell lors de la conférence Build 2013, porte volontairement sur des éléments non cruciaux, ou utiles à la limite dans des conditions de débogage mais pas dans le cadre du développement au jour le jour. Pour plus d'informations pratiques, merci de se référer à la première partie, résumé des points clés par InfoQ.

Le marshalling

Le marshalling est le terme consacré dans le monde COM pour désigner la possibilité d'utiliser un objet depuis un autre thread ou un autre processus. La plupart des objets WinRT ne requièrent pas de marshalling et ceux qui en ont besoin sont généralement conçus pour masquer au développeur le code lié au marshalling. On peut citer par exemple l'utilisation de la boite de dialogue FileOpen, qui marshale un appel au System Broker, un composant de l'OS.

Une différence intéressante entre COM, en client lourd, et WinRT, c'est la nature "agile" des proxies dans WinRT. Par "agile", on entend que le proxy à l'objet externe (comme le dialogue FileOpen) peut être déplacé en toute liberté, de thread en thread, sans aucun marshalling. Les appels du proxy à l'objet réel sont, eux, bien sûr marshalés.

Les interfaces IMarshal et INoMarshal sont utilisées pour indiquer le fait que l'objet veut participer ou pas au marshalling. Les objets WinRT ne sont généralement pas candidats au marshalling puisqu'ils sont la plupart du temps soit des objets UI, soit des objets agiles : les objets UI ne peuvent être appelés que par le thread UI (de sorte que tout marshalling est fait via le Dispatcher plutôt qu'au niveau des objets) et, en ce qui concerne les objets agiles, à nouveau, ils n'ont pas à être marshalés, par définition.

Il faut noter que les concepts de "thread-safe" et "agile" ne sont pas liés. Si un objet agile a la possibilité d'être appelé de n'importe quel thread, cela ne veut pas dire qu'il peut être appelé sans risque de façon concurrente par plusieurs threads.

Dans les rares cas où le marshalling est requis, le système d'exploitation génèrera le code correct à partir des données MIDL générées.

Les threads du thread pool

Les threads créés par le runtime WinRT sont toujours initialisés en tant que threads WinRT, sauf si ils ont été créés comme étant des threads UI. Ceci permet d'éviter la myriade d'options, telles que CoInitiailzeEx, proposées pour la création d'un thread, que l'on retrouve dans le monde COM client lourd.

Les opérations asynchrones initialisées sur un thread UI reprendront sur le thread UI une fois l'opération accomplie. Mais ce n'est pas une fonctionnalité du runtime, ce comportement est initié par les primitives asynchrones proposées par le langage de programmation comme create_task, await et promise.

Les opérations asynchrones initialisées sur un thread du thread pool seront complétées sur un thread quelconque, récupéré par l'OS pour effectuer la tâche asynchrone ou retourner son message de complétion.

Les objets agiles

Comme mentionné plus haut, les objets agiles sont des objets pouvant être déplacés librement d'un thread à l'autre, sans marshalling. En C++ et C#, ce sont des objets "normaux". Les objets agiles ne peuvent "stocker" que d'autres objets agiles. Si vous souhaitez stocker un IUnknow ou un IInspectable sans être certain que l'objet sous-jacent est bien un objet agile, vous devez l'encapsuler dans une référence agile.

Il est plus facile de travailler avec des objets agiles qu'avec des objets non-agiles, en partie parce qu'ils ne "meurent" pas lorsque le thread qui les héberge meurt. En comparaison, avec les clients lourds COM, vous devez garder le thread de l'objet sous le coude pour effectuer des tâches comme l'activation de la pompe à message.

Si vous voulez savoir au runtime si un objet est agile, vous pouvez le tester par rapport à l'interface IAgileObject. Si l'objet n'implémente pas cette interface, vous avez la possibilité d'utiliser la fonction RoGetAgileReference pour obtenir une IAgileReference. Cette fonction est une nouveauté de WinRT 8.1. Auparavant, il était nécessaire d'utiliser la table d'interface globale.

Les appartements

Les appartements sont des concepts COM liés à la gestion du cycle de vie des threads et des objets. Comprendre le concept d'appartement était crucial pour le développement des clients lourds des années 90. Même pour Visual Basic 6, qui était essentiellement à thread unique, une compréhension basique des modèles d'appartements COM était nécessaire.

Marytn Lovell les décrit ainsi :

Les appartements sont des concepts COM qui causent des soucis et font que des choses embêtantes se passent à des moments embêtants de façon inattendue.

Un des objectifs clés de WinRT était de faire en sorte que vous ne sachiez même pas que les appartements existent. Ceci dit, ils existent bel et bien et, pour les curieux, trois types d'appartements sont supportés par les applications WinRT :

  • ASTA : Application Single Threaded Apartment, les threads UI
  • MTA : Multi-threaded Apartment, les threads du thread pool
  • NTA : Neutral-threaded Apartment, des helpers pour les appels interprocessus

Cycle de vie des objets et threads

Si vous êtes un développeur JavaScript ou .NET, vous savez peut être que le cycle de vie d'un objet est lié à son appartement et à son thread. Donc si un appartement est accidentellement interrompu, ses objets, proxies et références agiles le seront aussi.

Marytn revient souvent sur ce sujet pour mieux souligner, avec satisfaction, que ces problèmes n'existent pas avec WinRT, en grande partie. Comme mentionné précédemment, les objets agiles permettent au développeur de contrôler le cycle de vie des objets, plutôt que de laisser cela sous la responsabilité de l'appartement ou du thread. En gros, le seul moment où vous pourriez vous inquiéter d'avoir un proxy déconnecté, c'est dans le cas où quelqu'un arrêterait manuellement un processus comme celui du System Broker.

Appels Cross-threads

Lorsque des messages sont délivrés à un thread, il y a souvent de la contention : lequel délivrer, dans quel ordre ? Par exemple, l'utilisateur peut appuyer sur des touches alors qu'un handler de clic de souris est en cours d'exécution. De par la conception de Windows 8, des pressions de touches peuvent être perdues quand la file d'entrée est bloquée. Windows 8.1 corrige, ou du moins améliore, ce comportement en faisant en sorte que la file d'entrée soit pas bloquée et que les évènements ne soient pas écartés par COM. Les tâches peuvent aussi être priorisées dans le planificateur utilisé par Windows 8.1

Les informations présentées dans cet article viennent de la session de la Build 2013 intitulée Windows Runtime Internals : Understanding the Threading Model.

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT