Verrous

Il est possible que plusieurs tâches dans le système aient besoin d'accéder au même objet pour le manipuler. ILock définit le protocole permettant d'octroyer un accès exclusif à un objet partagé. Lorsqu'une tâche doit accéder à l'objet partagé, il acquiert un verrou pour cet objet. Lorsqu'il a fini de manipuler l'objet, il libère le verrou.

Un verrou est généralement créé lorsque l'objet partagé est créé ou qu'un plug-in y accède pour la première fois. En d'autres termes, le code qui possède une référence à l'objet partagé, possède également une référence à son verrou. Nous commençons par créer un verrou, myLock, qui sera utilisé pour contrôler l'accès à myObject :

   ...
   myObject = initializeImportantObject();
   IJobManager jobMan = Platform.getJobManager();
   myLock = jobMan.newLock();
   ...

Une implémentation robuste de ILock est proposée par la plate-forme. Le gestionnaire de tâches met à disposition des instances de ce verrou qui sont utilisées par les clients. Ces verrous connaissent l'existence les uns des autres et peuvent éviter tout blocage circulaire (nous examinerons cet aspect plus en détail dans un moment).

Lorsque le code d'une tâche doit accéder à myObject, il doit d'abord acquérir le verrou qui y est associé. Le fragment de code ci-dessous affiche un moyen courant pour utiliser un verrou :

...
// Je dois manipuler myObject, donc je commence par acquérir son verrou.
try {
	myLock.acquire();
	updateState(myObject);  // pour manipuler l'objet
	} finally {
	lock.release();
}
...

La méthode acquire() ne renvoie rien tant que la tâche qui appelle ne peut pas recevoir un accès exclusif au verrou. En d'autres termes, si une autre tâche a déjà acquis le verrou, ce code est bloqué tant que le verrou n'est pas disponible. Notez que le code qui acquiert le verrou et manipule myObject est encapsulé dans un bloc try afin que le verrou puisse être libéré si une exception est générée lors de l'utilisation de l'objet.

L'opération a l'air simple. Heureusement, les verrous sont plutôt simples à utiliser. Ils sont également réentrants, ce qui signifie que vous n'avez pas besoin de vous soucier du fait que la tâche acquière le même verrou plusieurs fois. Chaque verrou enregistre le nombre de fois où il est acquis et libéré pour une unité d'exécution en particulier, et n'est libéré pour une tâche que lorsque le nombre d'acquisitions est égal au nombre de libérations.

Blocage

Vous avez noté précédemment que les verrous fournis par le gestionnaire de tâches connaissent l'existence les uns des autres et peuvent éviter les blocages circulaires. Pour comprendre comment un blocage se produit, observez ce scénario simple. Imaginez que la "tâche A" acquière le "verrou A" et tente ensuite d'acquérir le "verrou B". Entre-temps, le "verrou B" est acquis par la "tâche B" qui est bloquée en attente du "verrou A". Ce type de blocage indique un problème de conception sous-jacent en cas d'utilisation des verrous entre les tâches. Tandis que ce cas simple peut être évité assez facilement, les risques de créer un blocage par accident augmentent à mesure que le nombre de tâches et de verrous utilisés dans la conception prend de l'importance.

Heureusement, la plate-forme vous aide à identifier les blocages. Lorsque le gestionnaire de tâches détecte une condition de blocage, il imprime des informations de diagnostic dans le journal qui décrit la condition de blocage. Ensuite, le blocage est détruit en accordant temporairement l'accès aux verrous appartenant à une tâche bloquée à d'autres tâches en attente de ces verrous. Il est important de tester soigneusement toute implémentation impliquant plusieurs verrous et de corriger les conditions de blocage qui sont signalées par la plate-forme.