Après « l'exemple d'école » des Types Abstraits de données : la pile, on présente « l'exemple d'école » du parallélisme : il s'agit de l'exemple des lecteurs-écrivains, qu'on traite ici avec une priorité égale pour les lecteurs et les écrivains.
1. La spécification du problème
La réalisation des ressources demande de définir le type ressource-double et les procédures reserve, free et test.
Le type
Un aspect du problème, qui n'est pas apparu sur le réseau de Petri, est l'accès concurrent des procédures aux « variables d'état » de la ressource. Dans un réseau de Petri, le déclenchement d'une transition est « instantané » : la mise à jour du nombre de jetons dans les places concernées est indivisible ; dans une implantation, chaque étape de la mise à jour est différenciée – on a plusieurs instructions – et la mise à jour complète peut être interrompue – du moins si le moniteur est préemptif. Pour réaliser cette indivisibilité du déclenchement on utilise donc une ressource simple, à un point d'entrée unique.
TYPE ressource: RECORD
P,Q : integer;
c : integer;
acces : resource(1);
END RECORD;
P,Q sont les paramètres des ressources précédents ;c va être le nombre de points d'entrée occupés (initialement c=0) ;acces est une ressource simple (type resource) à un point d'entrée qui permet l'accès exclusif aux autres champs de la structure.Les procédures
Les procédures ont alors toutes un schéma de construction voisin : pour une ressource double R, on a :

On pourrait être "tenté" de réaliser ...recommencer... en "entourant" le traitement d'une boucle infinie, qui teste la condition jusqu'à ce qu'elle devienne vraie.
Par exemple :

On voit tout de suite que la solution ne convient pas, puisqu'on est à l'intérieur du bloc d'accès exclusif de la ressource et donc qu'aucune tâche ne pourra jamais modifier les valeurs des champs de la ressource, ce qui rendrait éventuellement la condition vraie.
D'une façon naturelle, on est alors conduit à placer la boucle infinie "au-dessus" du bloc d'accès exclusif. A chaque itération, on libère puis on réserve à nouveau la ressource d'accès exclusif ; une autre tâche pourra donc se glisser dans l'intervalle (on réalise ici une attente active : pour un fonctionnement correct il faut supposer que la tâche n'est pas super-prioritaire, parce qu'elle ne serait alors jamais interrompue) :

| (1) | Dans le contexte de la boucle /boucle/, on peut quitter la boucle par une phrase EXIT. |
| (2) | Dans le contexte du bloc de réservation, un « sortie brutale » (phrases EXIT ou RETURN) est précédée d'une libération de la ressource. |
La représentation « textuelle »
A un niveau de détail fin, on pourrait gérer le contexte dans lequel s'effectue la « sortie brutale » d'une boucle : cela nécessite inévitablement de travailler sur les arbres syntaxiques du langage, pour connaître la sémantique des "bouts de code" qu'on manipule (cf. Chapitre 3.3, « L'édition syntaxique »).
A un niveau plus grossier d'analyse du programme, on ne peut pas déduire des contraintes d'ordre contextuel ; en revanche on peut offrir à l'utilisateur le moyen de les exprimer. Cela signifie qu'on ne propose pas un mécanisme de déduction qui construise ou complète le programme mais plutôt un mécanisme de déclaration qui demande à l'utilisateur de réaliser lui-même les déductions mais qui permet aussi d'en conserver la trace.
La boucle qu'on retrouve dans tous les cas permet de décomposer la vue du corps d'une procédure en deux parties :

Conclusion
L'exemple est simple ; il présente une petite difficulté qu'on résout en prenant soin, à la rédaction du programme, de ne pas oublier le contexte dans lequel on est placé – ici dans une zone d'exclusion mutuelle.
La représentation « textuelle » fournit in extenso le texte source qu'on est assez naturellement conduit à construire. Cependant elle permet aussi de fixer, dans la Représentation Interne du texte source, la contrainte contextuelle qu'on a respectée ; à la relecture du programme, et à plus forte raison à sa correction on se rappellera cette contrainte, parce qu'elle est contenue dans le support même de m'information.
Corps des ressources doubles
BODY OF ressources-doubles;
PROCEDURE Initialiser( R:INOUT ressource-double; max_reserve,max_free:IN integer );
BEGIN
R.P := max_reserve;
R.Q := max_free;
R.c := 0;
free( R.acces );
END;
PROCEDURE reserve( R:INOUT ressource-double );
BEGIN
WHILE true DO /boucle/
reserve( R.acces );
IF R.c<R.P THEN
incr( R.c );
free( R.acces );
EXIT boucle;
END IF;
free( R.acces );
END DO;
END;
PROCEDURE test( R:INOUT ressource-double );
BEGIN
WHILE true DO /boucle/
reserve( R.acces );
IF R.c<R.Q THEN
NONE;
free( R.acces );
EXIT boucle;
END IF;
free( R.acces );
END DO;
END;
PROCEDURE free( R:INOUT ressource-double );
BEGIN
WHILE true DO /boucle/
reserve( R.acces );
IF R.c>0 THEN
decr( R.c );
free( R.acces );
EXIT boucle;
END IF;
free( R.acces );
END DO;
END;
END BODY;