Threading managé et non managé dans Windows

La gestion de tous les threads s'effectue par le biais de la classe Thread , notamment les threads créés par le Common Language Runtime et ceux créés en dehors du runtime qui entrent dans l'environnement managé pour exécuter du code. Le runtime surveille tous les threads dans son processus qui ont exécuté du code dans l'environnement d'exécution managé. Il n'effectue le suivi d'aucun autre thread. Les threads peuvent entrer dans l’environnement d’exécution managé via COM Interop (car le runtime expose les objets managés en tant qu’objets COM à l’environnement non managé), la fonction COM DllGetClassObject et l’appel de code non managé.

Quand un thread non managé entre dans le runtime via, par exemple, un wrapper CCW (COM Callable Wrapper), le système vérifie si le magasin de threads local de ce thread contient un objet Thread managé interne. Si un objet de ce type est trouvé, le runtime connaît déjà ce thread. Sinon, le runtime crée quand même un objet Thread et l’installe dans le magasin de threads local de ce thread.

Dans le modèle de thread managé, Thread.GetHashCode identifie les threads managés de manière stable. Durant toute la durée de vie de votre thread, cette identification n'entre en conflit avec la valeur d'aucun autre thread, quel que soit le domaine d'application à partir duquel vous obtenez cette valeur.

Correspondance entre les éléments de thread Win32 et les éléments de thread managés

Le tableau suivant établit une correspondance entre les éléments de thread Win32 et leurs équivalents approximatifs dans le runtime. Notez que cette mise en correspondance ne représente pas des fonctionnalités identiques. Par exemple, TerminateThread n’exécute pas de clauses finally ou ne libère pas de ressources, et son exécution ne peut pas être empêchée. Toutefois, Thread.Abort exécute tout votre code de restauration, récupère toutes les ressources et peut être refusé à l'aide de ResetAbort. Veillez à lire la documentation attentivement avant d'émettre des hypothèses sur les fonctionnalités.

Dans Win32 Dans le Common Language Runtime
CreateThread Combinaison de Thread et ThreadStart
TerminateThread Thread.Abort
SuspendThread Thread.Suspend
ResumeThread Thread.Resume
Veille Thread.Sleep
WaitForSingleObject sur le descripteur de thread Thread.Join
ExitThread Pas d'équivalent
GetCurrentThread Thread.CurrentThread
SetThreadPriority Thread.Priority
Pas d'équivalent Thread.Name
Pas d'équivalent Thread.IsBackground
Proche de CoInitializeEx (OLE32.DLL) Thread.ApartmentState

Threads managés et cloisonnements COM

Un thread managé peut être marqué pour indiquer qu’il hébergera un thread unique cloisonné ou un multithread cloisonné. (Pour plus d’informations sur l’architecture de threads COM, consultez Processus, threads et cloisonnements.) Les méthodes GetApartmentState, SetApartmentState et TrySetApartmentState de la classe Thread retournent et attribuent l’état de cloisonnement d’un thread. Si l'état n’a pas été défini, GetApartmentState retourne ApartmentState.Unknown.

La propriété ne peut être définie que quand le thread se trouve dans l’état ThreadState.Unstarted et qu’une seule fois par thread.

Si l'état de cloisonnement n'est pas défini avant que le thread n'ait démarré, celui-ci est initialisé en tant que cloisonnement multithread (MTA). Le thread finaliseur et tous les threads contrôlés par ThreadPool sont des threads MTA.

Important

Pour le code de démarrage d'application, la seule façon de contrôler l'état de cloisonnement consiste à appliquer les attributs MTAThreadAttribute ou STAThreadAttribute à la procédure de point d'entrée.

Les objets managés exposés à COM se comportent comme s’ils avaient agrégé le marshaleur libre de threads. En d'autres termes, ils peuvent être appelés depuis n'importe quel cloisonnement COM d'une manière libre de threads. Les seuls objets managés qui ne présentent pas ce comportement libre de threads sont les objets qui dérivent de ServicedComponent ou StandardOleMarshalObject.

Dans l'environnement managé, l'attribut SynchronizationAttribute n'est pas pris en charge, sauf si vous utilisez des contextes et des instances managées liées au contexte. Si vous utilisez Enterprise Services, votre objet doit dériver de ServicedComponent (lui-même dérivé de ContextBoundObject).

Quand un code managé appelle des objets COM, il suit systématiquement les règles COM. En d'autres termes, il effectue les appels par le biais de proxys de cloisonnement COM et de wrappers de contexte COM+ 1.0, conformément à OLE32.

Problèmes de blocage

Si un thread effectue dans le système d'exploitation un appel non managé et qu'il se retrouve bloqué dans un code non managé, le runtime ne prend pas le contrôle du thread pour Thread.Interrupt ou Thread.Abort. Dans le cas de Thread.Abort, le runtime marque le thread comme Abandonné et en prend le contrôle quand il revient dans le code managé. Pensez à utiliser un blocage managé plutôt qu'un blocage non managé. WaitHandle.WaitOne,WaitHandle.WaitAny, WaitHandle.WaitAll, Monitor.Enter, Monitor.TryEnter, Thread.Join, GC.WaitForPendingFinalizers, etc. réagissent tous à Thread.Interrupt et à Thread.Abort. En outre, si votre thread se trouve dans un cloisonnement monothread, toutes ces opérations de blocage managé pompent correctement les messages dans votre cloisonnement pendant que votre thread est bloqué.

Threads et fibres

Le modèle de thread .NET ne prend pas en charge les fibres. Vous ne devez pas appeler dans n’importe quelle fonction non managée qui est implémentée à l’aide de fibres. Ces appels peuvent entraîner un blocage du runtime .NET.

Voir aussi