VB cherche appartement
Qui n'a jamais joué avec les propriétés de compilation de VB 6.0 pour se retrouver devant le grand mystère de l'option Threading Model : Apartment Thread et Single Threaded ?
Vous comme moi, vous avez laissé la valeur par défaut, à savoir Apartment et vous avez eu raison.
Par curiosité, vous avez cherché ce que cela signifiait pour toujours retomber sur la différence entre le Single Threaded Apartment (STA) et le Multi Threaed Apartment (MTA).
Et là, tout s'embrouille : Single Threaded Apartment = Apartment Thread ou Single Threaded ?
Les deux ?
Où se trouve l'option MTA en VB ?
STA vs MTA
Bon, Single Threaded Apartment = Apartment Thread.
Laissons de côté le Single threaded qui relève plutôt de la compatibilité ascendante.
Quand à MTA, ca n'existe pas en VB. Est ce pour autant réservé à .NET ? Non, le C++ peut être MTA mais jamais le VB.
Est ce que cela signifie que VB est mono thread ?
Non parceque mono thread, c'est l'option Single Threaded.
Alors ca veut dire quoi STA si ce n'est ni multi thread ni mono thread ?
Apartment signifie conteneur cloisonné. Le thread STA est isolé du reste du monde. Il a sa pile d'appel à lui, sa mémoire allouée etc...
On peut avoir plusieurs threads STA (on parle alors de pooled STA) mais ils seront toujours cloisonnés, isolés les uns des autres.
C'est le cas, par exemple, dans IIS puisqu'il autorise en ASP/VB les appels multiples.
Donc, ce n'est pas du multi thread mais ca peut être exécuté en plusieurs instances en parallèle. Quelle est la différence avec le thread MTA alors ?
En MTA, il y aussi un apartement (Multi Threaded Apartment) mais il est commun à tous les threads. On parle alors de décloisonnement au sein de l'apartement MTA : tous les threads partagent tout entre eux. Mais vis à vis du reste du monde, l'apartment MTA est cloisonné.
Cette différence de cloisonnement produit deux effets :
En STA, pour passer d'un apartment à un autre, il faut opérer un switch de thread et transférer tout son contexte d'exécution. Pour aller chez son voisin, il faut sortir de chez soi, fermer à clef, sonner, dire bonjour...
En MTA, pas de switch, l'immeuble est une grande communauté hippie où toutes les portes ont été supprimées.
Par contre, en STA, la synchronisation des composants est assurée de facto. Puisque les threads sont cloisonnés, il n'y a pas possibilité que deux threads accèdent simultanément à une même ressource.
Prenons le cas d'un fichier, il ne doit pas être possible d'écrire simultanément au même moment dans un unique fichier.
Prenons maintenant deux threads STA. Le fichier ne peut être monté en mémoire que par un des deux threads STA, disons le thread 1. Comme tout est cloisonné, le thread 2 n'a pas accès au fichier. Si il opère un switch de thread, il sera alors sérialisé avec le thread 1 car un apartment STA est mono tâche comme son nom l'indique.
Ce phénomène n'existe pas en MTA et la synchronisation doit être assurée par le code lui même. On parle alors de code thread safe comme on le voit souvent dans la doc MSDN.
Prenons l'exemple du pattern singleton :
Le singleton assure qu’un objet est créé une seule et unique fois. Par la suite, la même instance sera toujours réutilisée.
Si le code de création de l'instance unique n'est pas thread safe, il est théoriquement possible que deux threads sollicitent le singleton exactement au même moment, créant ainsi deux instances. Ce qui a des chances d'arriver dans un contexte de très forte sollicitation comme un site web par exemple.
Il y a possibilité de verrouiller le code de création du singleton en utilisant l'instruction lock.
On parle alors de singleton thread safe : http://msdn.microsoft.com/en-us/library/ms998558.aspx
Donc, pour faire simple :
STA = mono thread
STA poolé = multi thread cloisonnés
MTA = multi thread décloisonné
Interopérabilité avec ASP.NET
Par défaut, ASP.NET s'exécute en mode MTA. Si un composant VB est appelé, celui ci n'étant pas MTA compatible, un thread STA sera créé pour exécuter son code.
Premier problème : il y a forcément un swtich de thread pour passer de MTA à STA et inversement. Rappelez-vous le switch entre deux threads STA. Le même phénomène se produit pour passer de STA à MTA.
Second problème : par défaut, il n'y a qu'un seul thread STA pour tout le monde. En clair, tous les appels VB sont sérialisés dans un unique thread STA. En cas de forte charge, on créé immanquablement un goulot d'étranglement.
Dans notre communauté hippie, il n'y a qu'une seule salle de bain. Si la communauté prend de l'ampleur, il y a file d'attente pour se laver.
Comment alors profiter du pooling de thread STA ?
Il y a deux solutions : AspCompat et COM+ (Serviced application).
La directive de compilation AspCompat=true des pages aspx force ASP.NET à s'exécuter en STA poolé, comme le faisait ASP/VB. Cela va faire disparaitre le goulot d'étranglement mais va ralentir le code .NET car il ne sera plus exécuté en MTA qui est plus performant.
Heureusement, cette directive est une directive de page. Elle peut donc être ajustée au cas par cas, autorisant ainsi les pages full .NET à rester en MTA.
Il y a plusieurs salles de bain dans notre communauté hippie mais il n'y en a pas une dans chaque bâtiment et seuls les habitants du bâtiment peuvent l'utiliser.
La seconde solution consiste à glisser toutes vos dll dans le service de composant (anciennement MTS).
Pour cela, il faut d'abord créer l'application COM+.
Deux cas se présentent alors :
Le mode library va produire un effet similaire à la directive AspCompat mais sans possibilité d'ajustement par page. Peu d'interêt.
Le mode serveur va créer un processus STA poolé dédié aux appels COM nommé svchost. Tout le code VB y sera exécuté en mode STA et le code .NET restera en mode MTA dans le processus IIS w3wp.
Dans ce modèle idyllique le code .NET tourne en MTA et le code VB en STA poolé.
C'est idéal à condition que les appels VB ne soient pas fréquents car comme nous l'avons vu, le fait de passer MTA à STA provoque un switch de thread.
Pour que le gain apporté par le fait .NET tourne en MTA soit rentable, il ne faut pas qu'il soit noyé par la perte engendrée par le switch de thread.
L'idéal étant de tout regrouper dans un seul appel COM.
Notre communauté hippie s'est finalement transformé en camping et dispose de plusieurs salles de bain toutes regroupées dans un bâtiment spécifique.
Conclusion
En réalité, VB ne partage jamais son appartement et c'est bien là sa limite majeure et probablement une des raisons de la rupture brutale entre ASP/VB 6.0 et .NET. Car avant .NET, pour faire du vrai multi thread (non cloisonné), il fallait faire du C++ ce qui, nous en conviendrons, est moins accessible que VB 6.0.
Références : http://www.techvanguards.com/com/concepts/multithreading.asp
http://www.codeguru.com/cpp/com-tech/activex/apts/article.php/c5529#more
http://www.codeguru.com/cpp/com-tech/activex/apts/article.php/c5533
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :