Au moins en C ++, je pense que le thread-safe est un peu impropre en ce sens qu'il laisse beaucoup de côté du nom. Pour être thread-safe, le code doit généralement être proactif à son sujet. Ce n'est généralement pas une qualité passive.
Pour qu'une classe soit sécurisée, elle doit avoir des fonctionnalités "supplémentaires" qui ajoutent une surcharge. Ces fonctionnalités font partie de l'implémentation de la classe et sont généralement cachées de l'interface. C'est-à-dire que différents threads peuvent accéder à n'importe quel membre de la classe sans jamais avoir à se soucier des conflits avec un accès simultané par un thread différent ET peuvent le faire de manière très paresseuse, en utilisant un ancien style de codage humain ordinaire, sans avoir à le faire tout ce truc de synchronisation fou qui est déjà roulé dans le ventre du code appelé.
Et c'est pourquoi certaines personnes préfèrent utiliser le terme synchronisé en interne .
Ensembles de terminologie
Il y a trois ensembles principaux de terminologie pour ces idées que j'ai rencontrées. Le premier et historiquement le plus populaire (mais le pire) est:
- fil sûr
- pas sûr pour les threads
Le second (et mieux) est:
- résistant au fil
- compatible avec les fils
- fil hostile
Un troisième est:
- synchronisé en interne
- synchronisé en externe
- non synchronisable
Analogies
thread safe ~ thread proof ~ synchronisé en interne
Un exemple de système synchronisé en interne (aka. Thread-safe ou thread proof ) est un restaurant où un hôte vous accueille à la porte et vous empêche de faire la queue vous-même. L'hôte fait partie du mécanisme du restaurant pour traiter avec plusieurs clients et peut utiliser des astuces plutôt délicates pour optimiser l'assise des clients en attente, comme la prise en compte de la taille de leur fête ou le temps dont ils ont l'air. , ou même prendre des réservations par téléphone. Le restaurant est synchronisé en interne car tout cela fait partie de l'interface pour interagir avec lui.
pas compatible avec les threads (mais agréable) ~ compatible avec les threads ~ synchronisé en externe ~ libre
Supposons que vous alliez à la banque. Il y a une ligne, c'est-à-dire un conflit pour les caissiers. Parce que vous n'êtes pas un sauvage, vous reconnaissez que la meilleure chose à faire au milieu d'une dispute pour une ressource est de faire la queue comme un être civilisé. Personne ne vous oblige techniquement à le faire. Nous espérons que vous avez la programmation sociale nécessaire pour le faire vous-même. En ce sens, le lobby bancaire est synchronisé en externe. Faut-il dire que c'est thread-dangereux? c'est ce que cela implique si vous optez pour l' ensemble de terminologie bipolaire thread-safe et thread-unsafe . Ce n'est pas un très bon ensemble de termes. La meilleure terminologie est synchronisée en externe,Le lobby bancaire n'est pas hostile à l'accès de plusieurs clients, mais il ne fait pas non plus le travail de synchronisation. Les clients le font eux-mêmes.
Ceci est également appelé "filetage libre", où "libre" est comme dans "sans poux" - ou dans ce cas, les verrous. Eh bien, plus précisément, les primitives de synchronisation. Cela ne signifie pas que le code peut s'exécuter sur plusieurs threads sans ces primitives. Cela signifie simplement qu'il ne vient pas avec eux déjà installés et c'est à vous, l'utilisateur du code, de les installer vous-même comme bon vous semble. L'installation de vos propres primitives de synchronisation peut être difficile et nécessite une réflexion approfondie sur le code, mais peut également conduire au programme le plus rapide possible en vous permettant de personnaliser la façon dont le programme s'exécute sur les CPU hyperthreadés d'aujourd'hui.
pas sûr pour les threads (et mauvais) ~ hostile aux threads ~ non synchronisable
Un exemple d'analogie quotidienne avec un système hostile aux fils est celui d'un imbécile avec une voiture de sport refusant d'utiliser ses oeillères et de changer de voie à volonté. Leur style de conduite est hostile au fil ou non psychronisable car vous n'avez aucun moyen de vous coordonner avec eux, ce qui peut entraîner des conflits pour la même voie, sans résolution, et donc un accident car deux voitures tentent d'occuper le même espace, sans aucun protocole éviter cela. Ce modèle peut également être considéré plus largement comme antisocial, ce que je préfère car il est moins spécifique aux threads et donc plus généralement applicable à de nombreux domaines de la programmation.
Pourquoi thread safe et al. sont une mauvaise terminologie
Le premier et le plus ancien ensemble terminologique ne parviennent pas à faire la distinction plus fine entre l' hostilité des threads et la compatibilité des threads . La compatibilité des threads est plus passive que la soi-disant sécurité des threads, mais cela ne signifie pas que le code appelé n'est pas sûr pour une utilisation simultanée des threads. Cela signifie simplement qu'il est passif à propos de la synchronisation qui permettrait cela, le reportant au code appelant, au lieu de le fournir dans le cadre de son implémentation interne. La compatibilité avec les threads est la façon dont le code devrait probablement être écrit par défaut dans la plupart des cas, mais cela est malheureusement souvent souvent considéré à tort comme un thread non sécurisé, comme s'il était intrinsèquement anti-sécurité, ce qui est un point de confusion majeur pour les programmeurs.
REMARQUE: De nombreux manuels de logiciels utilisent en fait le terme «thread-safe» pour désigner «compatible thread», ajoutant encore plus de confusion à ce qui était déjà un gâchis! J'évite à tout prix les termes "thread-safe" et "thread-unsafe", car certaines sources appellent quelque chose "thread-safe" tandis que d'autres l'appelleront "thread-unsafe" parce qu'elles ne peuvent pas être d'accord si vous devez répondre à des normes de sécurité supplémentaires (primitives de synchronisation), ou simplement NE PAS être hostile pour être considéré comme "sûr". Évitez donc ces termes et utilisez plutôt les termes les plus intelligents, pour éviter de mauvaises communications dangereuses avec d'autres ingénieurs.
Rappel de nos objectifs
Essentiellement, notre objectif est de renverser le chaos.
Nous le faisons en créant des systèmes déterministes sur lesquels nous pouvons compter. Le déterminisme est coûteux, principalement en raison des coûts d'opportunité de la perte du parallélisme, du pipelining et de la réorganisation. Nous essayons de minimiser la quantité de déterminisme dont nous avons besoin pour maintenir nos coûts bas, tout en évitant de prendre des décisions qui éroderont davantage le peu de déterminisme que nous pouvons nous permettre.
La synchronisation des threads consiste à augmenter l'ordre et à réduire le chaos. Les niveaux auxquels vous le faites correspondent aux conditions mentionnées ci-dessus. Le niveau le plus élevé signifie qu'un système se comporte de manière entièrement prévisible à chaque fois. Le deuxième niveau signifie que le système se comporte suffisamment bien pour que le code appelant puisse détecter de manière fiable l'imprévisibilité. Par exemple, un réveil parasite dans une variable de condition ou un échec de verrouillage d'un mutex car il n'est pas prêt. Le troisième niveau signifie que le système ne se comporte pas assez bien pour jouer avec quelqu'un d'autre et ne peut être exécuté que sur un seul thread sans provoquer de chaos.