Wait et notify : objet appelant

Le problème exposé dans ce sujet a été résolu.

Yo !

J'ai une petite question, complémentaire à mon topic "Cet exercice est-il connu ?", qui concerne wait et notify.

Pour une raison encore obscure, il faut placer ces appels dans des sections critiques (synchronized). Ce n'est pas vraiment pour mieux connaître cette obscure raison que je crée ce topic, mais plutôt pour savoir :

  1. Si l'objet appelant wait et notify est TOUJOURS le même ;

  2. Si cet objet est TOUJOURS le même que celui placé en tant que verrou (ie. : synchronized(cetobjet) {...})

  3. J'ai lu dans un tutoriel sur Internet que objet.wait() lance la mise en attente du thread actuel par l'objet objet. Qu'est-ce que ça veut dire ? J'ai du mal à comprendre ce que ça représente au niveau du fonctionnement de wait ;

  4. Enfin, j'ai également lu dans un autre tuto que wait libère le verrou défini par sychronized(cetobjet) (ici le verrou est cetobjet). Je ne comprends pas ça non plus.

Voilà. Avec toutes ces questions, je me demande si j'ai bien compris le mécanisme wait et notify. Pourtant en soi, il n'y a rien de bien compliqué : wait met le thread A en attente d'un notify qui le réveille : les instructions suivant le wait sont alors exécutées (alors que si aucun notify n'est exécuté, elles ne le seront pas).

Bref si quelqu'un a le temps de répondre à ces 4 questions, ce serait sympa, vous m'avez déjà beaucoup aidé ! ^^

Merci encore !

Avant tout, petit rappel sur le fonctionnement d'un verrou : lors d'une demande d'acquisition, si le verrou est déjà pris, il met le processus qui a fait la demande en attente, et le réveille lorsque le verrou est libéré (si plusieurs processus sont en attente, un seul sera réveillé, et pas toujours le premier a avoir fait la demande sauf si le verrou est dit "équitable").

Pour une raison encore obscure, il faut placer ces appels dans des sections critiques (synchronized).

Pour des raisons évidentes de cohérence, utiliser wait et notify est interdit si tu n'as pas acquis le verrou de l'objet qui le fait au préalable, ce qui se fait en utilisant synchronized. Cf ici et la.

  1. Si l'objet appelant wait et notify est TOUJOURS le même ;

Oui.

  1. Si cet objet est TOUJOURS le même que celui placé en tant que verrou (ie. : synchronized(cetobjet) {...})

Oui.

  1. J'ai lu dans un tutoriel sur Internet que objet.wait() lance la mise en attente du thread actuel par l'objet objet. Qu'est-ce que ça veut dire ? J'ai du mal à comprendre ce que ça représente au niveau du fonctionnement de wait ;

wait met le thread appelant (celui qui a fait le wait) dans une liste de threads en sommeil. Il pourra ensuite être réveillé par une notification depuis un autre thread ou une interruption.

C'est une méthode liée a un objet, parce que c'est le verrou de l'objet en question qui va gérer la liste d'attente des threads en sommeil, et le réveil avec notify.

  1. Enfin, j'ai également lu dans un autre tuto que wait libère le verrou défini par sychronized(cetobjet) (ici le verrou est cetobjet). Je ne comprends pas ça non plus.

Pour que ça puisse marcher, il faut qu'un autre thread prenne la main sur le verrou qui gère la synchronisation, le thread doit donc impérativement libérer le verrou avant de s'endormir, et le reprendra lors de son réveil.

D'ailleurs, il faut bien comprendre qu'une notification ne réveille pas immédiatement le thread notifié, qui passe seulement dans une liste d'attente de threads prêts. Il ne prendra la main que lorsqu'il aura réussi a prendre le verrou.

Pour des raisons évidentes de cohérence, utiliser wait et notify est interdit si tu n'as pas acquis le verrou de l'objet qui le fait au préalable, ce qui se fait en utilisant synchronized. Cf ici et la.

Dans la JavaDoc et ailleurs, on parle de "moniteur". J'ai un peu de mal à comprendre ce que c'est précisément (Wikipédia dit que c'est l'ensemble formé par un verrou, par des fonctions utilisant une ressource partagée… mais la définition s'arrête là).

Peux-tu juste confirmer, ou infirmer, s'il te plaît, que le moniteur c'est le système interne à la JVM qui gère la notion d'exclusion mutuelle ? C'est-à-dire le système interne qui est caché au programmeur Java tel que moi et qui attribue le verrou d'un synchronized à tel ou tel thread et donc empêche les autres de le prendre.

D'un autre côté j'ai l'impression que "monitor" est directement synonyme de "verrou", à cause de cette phrase tirée de la JavaDoc : "Wakes up a single thread that is waiting on this object's monitor. "… Pourtant c'est censé être "lock" ou "bolt".

C'est quand même incroyable qu'il n'y ait pas un seul tuto parfaitement clair et facilement compréhensible qui explique cette notion, j'imagine que ce n'est pas très important… Donc désolé si je donne l'impression de chipoter en posant une question trop "pointue" mais j'aime bien connaître les choses en détails.

C'est une méthode liée a un objet, parce que c'est le verrou de l'objet en question qui va gérer la liste d'attente des threads en sommeil, et le réveil avec notify.

Heum un verrou peut vraiment gérer quelque chose ? Tu ne veux pas plutôt dire "moniteur" du coup ? (il y aurait donc bien une différence entre moniteur et verrou).

Si c'est le moniteur de l'objet appelant wait/notify qui gère ça, j'imagine qu'il y a au moins un critère pour choisir cet objet appelant. Peux-tu m'en dire plus si possible ? Est-ce que ce critère ne serait pas, par hasard, le suivant : "utiliser wait/notify de l'objet passé à synchronized(x)" ?

Aussi, j'aimerais bien savoir pourquoi =/

Pour que ça puisse marcher, il faut qu'un autre thread prenne la main sur le verrou qui gère la synchronisation, le thread doit donc impérativement libérer le verrou avant de s'endormir, et le reprendra lors de son réveil.

"Cet autre thread" dont tu parles, c'est un thread contenant notify ? Si oui, j'ai bien compris ton explication : le thread mis en attente doit en effet libérer le verrou pour que l'autre thread le notifiant puisse le notifier, étant donné que tous deux ont le même verrou synchronized(objet)).

D'ailleurs 4è ou 5è question de ce post ^^' : le verrou peut-il se trouver dans une classe A et dans une classe B, toutes deux héritant de Thread ? Du coup un thread :B pourrait réveiller un thread :A.

Voilà désolé de poser autant de questions… Merci encore !

les termes que j'emploie ne sont pas forcement exacts du point de vue de Java, je laisse les précisions terminologiques a quelqu'un de plus pointu sur le sujet.

Dans la JavaDoc et ailleurs, on parle de "moniteur". J'ai un peu de mal à comprendre ce que c'est précisément (Wikipédia dit que c'est l'ensemble formé par un verrou, par des fonctions utilisant une ressource partagée… mais la définition s'arrête là).

Pour comprendre le concept de moniteur et son intérêt, une bonne idée peut être de lire le papier original de Hoare (Monitors: an operating system structuring concept - 1974).

En Java, les moniteurs sont moins puissants (ils ne gèrent qu'une seule file d'attente), mais le concept reste très proche : le mot clé synchronized permet de protéger de façon transparente une portion de code contre l’accès concurrent. En réalité, c'est un verrou interne qui est utilisé, a la fois pour gérer l’accès et les primitives wait et notify.

Peux-tu juste confirmer, ou infirmer, s'il te plaît, que le moniteur c'est le système interne à la JVM qui gère la notion d'exclusion mutuelle ? C'est-à-dire le système interne qui est caché au programmeur Java tel que moi et qui attribue le verrou d'un synchronized à tel ou tel thread et donc empêche les autres de le prendre.

Le "moniteur" est le mécanisme général (verrou + file d'attente), pas juste le truc qui attribue le verrou.

D'un autre côté j'ai l'impression que "monitor" est directement synonyme de "verrou", à cause de cette phrase tirée de la JavaDoc : "Wakes up a single thread that is waiting on this object's monitor. "… Pourtant c'est censé être "lock" ou "bolt".

C'est quasiment synonyme, comme vu plus haut.

Heum un verrou peut vraiment gérer quelque chose ? Tu ne veux pas plutôt dire "moniteur" du coup ? (il y aurait donc bien une différence entre moniteur et verrou).

Peu importe le nom, je parlais des verrous internes aux objets de java, pas des objets Lock (qui s'utilisent autrement).

Le mécanisme de file d'attente est obligatoirement associé a un verrou (directement ou non, je n'en sais rien), c'est ce qui permet de mettre les autres threads en attente du verrou s'il est déjà pris.

Si c'est le moniteur de l'objet appelant wait/notify qui gère ça, j'imagine qu'il y a au moins un critère pour choisir cet objet appelant. Peux-tu m'en dire plus si possible ? Est-ce que ce critère ne serait pas, par hasard, le suivant : "utiliser wait/notify de l'objet passé à synchronized(x)" ?

Bien sur, et ce n'est pas un hasard, il faut absolument que le verrou (ou moniteur si tu veux) soit le même entre wait et notify.

Aussi, j'aimerais bien savoir pourquoi =/

Chaque verrou est associé a sa propre file d'attente (sinon, bah ce serait le bordel, tu ne sais plus qui tu va notifier).

"Cet autre thread" dont tu parles, c'est un thread contenant notify ?

Oui, pour que notify puisse passer, il faut que le thread appelant ait la main.

D'ailleurs 4è ou 5è question de ce post ^^' : le verrou peut-il se trouver dans une classe A et dans une classe B, toutes deux héritant de Thread ? Du coup un thread :B pourrait réveiller un thread :A.

Encore une fois, un verrou n'est pas spécialement lié a un thread, mais peut se trouver dans n'importe quel autre objet. Donc oui, n'importe quel thread peut réveiller n'importe quel objet.

Attention de ne pas confondre le code du Thread et code exécuté par ce thread. D'ailleurs, un thread exécute souvent le code d'un objet Runnable.

+0 -0

Le "moniteur" est le mécanisme général (verrou + file d'attente), pas juste le truc qui attribue le verrou.

Ok c'est à peu près ce que je pensais alors, merci ! (juste : "file d'attente" = file où sont rangés les threads qui attendent la libération du verrou OU BIEN celle où sont rangés les threads qui attendent un notify ou encore les deux ? =/)

Merci beaucoup pour tous ces éclaircissements. J'trouve ça dommage qu'aucun tuto Web n'apporte ces explications, qui peuvent paraître pointilleuses mais bon.

(juste : "file d'attente" = file où sont rangés les threads qui attendent la libération du verrou OU BIEN celle où sont rangés les threads qui attendent un notify ou encore les deux ? =/)

Je ne sais pas trop comment ça fonctionne en interne (et c'est probablement implementation defined).

Ce qui est sur, ce que l’état d'un thread est différent selon s'il a fait wait ou est simplement en attente du verrou (cf. ici), ce qui est logique puisque l'un sera activé dès que le verrou devient libre, alors que l'autre a besoin d'une notification pour être réveillé (il passe alors en BLOCKED, et n'est pas forcement activé tout de suite). Donc il peut très bien y avoir 2 files d'attente distinctes.

Note également que le terme "file d'attente" est un léger abus de langage, rien ne garantit que les threads seront servis dans l'ordre des demandes (l’équitabilité n'est pas garantie). D'ailleurs, la doc parle de wait set et non de queue.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte