Quelles représentations intermédiaires peuvent être utilisées pour raisonner sur la concurrence?


12

J'essaie de mieux comprendre ce qui serait nécessaire pour qu'un compilateur puisse faire des choix intelligents concernant la concurrence au nom du programmeur. Je me rends compte qu'il existe de nombreux aspects difficiles de ce problème, par exemple:

  • S'assurer qu'il n'y a pas de conditions de course
  • S'assurer que le code à exécuter simultanément n'aura pas d'effets secondaires qui auront un impact sur la signification sémantique du code

  • Décider si le surcoût de la rotation des threads est utile compte tenu du degré de parallélisme disponible dans le code

Ma compréhension est que les deux principales représentations intermédiaires utilisées dans les compilateurs modernes sont l'affectation unique statique pour les langages procéduraux et orientés objet et les continuations passant le style pour les langages fonctionnels. Il est difficile de raisonner sur l'un des problèmes énumérés ci-dessus en utilisant ces formes intermédiaires. Même les langages qui devraient en théorie avoir les meilleures chances de parallélisation automatique (les langages fonctionnels purs comme Haskell avec une garantie sans effets secondaires) ont fait des progrès limités sur ce front.

Donc ma question est vraiment quelles représentations intermédiaires ont été utilisées pour essayer de résoudre ce problème? Y a-t-il d'autres représentations qui ont été utilisées dans la recherche universitaire que je ne connais pas qui sont mieux adaptées à cette tâche? Ce problème doit-il être fondamentalement résolu par le frontal du compilateur en manipulant l'arbre de syntaxe abstraite avant que la compilation n'atteigne une représentation intermédiaire?


Si vous écrivez votre code de manière fonctionnelle, vous n'aurez pas à vous soucier des conditions de course ou des effets secondaires.
Robert Harvey

4
Cela ne répond pas tout à fait à votre question, mais vous pourriez être intéressé par Process Calculi qui peut être utilisé pour raisonner sur le code concurrent. L'exemple le plus connu pourrait être le Pi Calculus . Cependant, la parallélisation automatique est toujours un problème en grande partie non résolu et il est préférable de le résoudre en concevant des langages spécifiquement pour fournir au compilateur certaines garanties, ou en utilisant des annotations spéciales.
amon

4
Le document qui sert de toile de fond pour les collections simultanées Intel (CnC) répertorie huit modèles concurrents fondamentaux, tels que Producer-Consumer. Ces modèles simultanés dépendent à leur tour d'un certain nombre de propriétés, telles que l'immuabilité et l'absence d'effets secondaires. (J'apprécierais que quelqu'un puisse résumer ce document et le poster comme réponse ici.)
rwong

L'un des outils théoriques est appelé "Dynamic Single Assignment (DSA)", construit au-dessus de SSA.
rwong

@rwong: pouvez-vous fournir une référence explicite?
Ira Baxter

Réponses:


5

On supposerait que la modélisation de la concurrence explicite dans la représentation intermédiaire (IR) était une exigence nécessaire. Ainsi, une réponse serait «tout IR utilisé pour des programmes séquentiels avec l'ajout de certaines opérations de concurrence», par exemple, «fork and join», «parallel x y». Leur ajout permet de raisonner sur certains types de simultanéité, mais pas nécessairement facilement. Il n'est pas non plus évident de savoir comment garantir certaines propriétés (absence de course de données) sans aller jusqu'à une représentation entièrement fonctionnelle (ce qui rend difficile la modélisation utile du parallélisme).

On peut dire que les réseaux de Petri colorés (CPN) sont un bon choix pour représenter des programmes avec accès simultané. (Les jetons dans les CPN sont "colorés" [ont un type] et peuvent porter des valeurs; les "transitions" dans les états peuvent effectuer une arithmétique arbitraire sur les jetons entrants pour produire un jeton éventuellement de couleur différente avec une valeur calculée à la "place"). Si vous pensez que les lieux sont des résultats calculés et des transitions en tant qu'opérateurs de modélisation (y compris un opérateur spécial pour accéder à la mémoire), cela vous donne ce qui équivaut à un graphique de flux de données avec lequel modéliser des programmes. Vous pouvez facilement l'utiliser pour donner une interprétation formelle aux représentations classiques du compilateur telles que les triplets [opérateur, entrée1, entrée2, sortie].

Il existe de nombreux outils pour analyser ces graphiques CPN, y compris les propriétés de calcul telles que l'impasse sans blocage, la limitation du nombre de jetons par endroits, etc. Les CPN hiérarchiques vous permettent de modéliser des fonctions et des procédures et la notion d '"appels".

Ce que ces représentations ne font pas clairement, c'est de faciliter la réflexion sur l'endroit où l'on pourrait paralléliser une application. Trivialement, deux sous-calculs peuvent être parallèles s'ils n'effectuent pas d'opérandes partagés (c'est pourquoi certaines personnes aiment les programmes / représentations fonctionnels). Si la représentation de votre programme modélise une mémoire partagée, vous pouvez la modéliser comme un monolithe et obtenir l'ensemble habituel de problèmes de raisonnement sur les interactions sur la mémoire partagée, y compris l'adressage aliasé, etc. Une façon d'éviter cela est de traiter la mémoire comme des morceaux isolés avec le plus grand état du programme étant un assemblage (semblable à un arbre) de ceux-ci; vous pouvez sans doute passer ces morceaux dans votre représentation intermédiaire. Il n'y a pas d'interaction entre deux calculs parallèles s'ils ne partagent pas de morceaux (par exemple, des sous-arbres de mémoire).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.