Je ne parle pas en général, mais dans ce cas bien précis.
Tu fais à mon avis l'erreur de penser que beginSheetWithDirectory fait plus que ce qu'elle fait réellemement: elle ne fait qu'instancier une fenêtre et l'afficher, rien de plus.
Je sais, et cette partie ne m'intéresse pas... C'est la partie qui consiste à attendre une réponse de l'utilisateur qui m'intéresse particulièrement ! Car cette attente se fait forcément par une boucle qui ne fait quasiment rien tout en monopolisant le thread.
Or pendant cette attente, la fonction qui a appelé "beginSheetWithDirectory" continue, et c'est ça qui me fait dire que l'attente est gérée par un second thread.
(Mais tu as raison, l'affichage peut être géré par le thread principal, panipwoblèm !)
Non la fonction qui appelle beginSheetWithDirectory continue normalement, vu que cette méthode n'est pas bloquante. Et donc une fois que son exécution est finie, l'appli se remet normalement en état d'attente d'événement, mais simplement ignorera les événements relatifs à la fenêtre parent.
En d'autres termes, le thread principal lance le "beginSheetWithDirectory" et continue. Il termine l'exécution de la méthode et retourne sa phase d'attente d'événèment.
En d'autres termes, le thread principal lance le "beginSheetWithDirectory" et continue. Il termine l'exécution de la méthode et retourne sa phase d'attente d'événèment.
OK, comme ça ça peut se concevoir je l'accorde (si on considère que l'attente de la réponse ne se fait qu'après la fin de la fonction d'origine ; même si ça ne me paraà®t pas super logique)... Je vais donc faire un projet qui charge un nib de la même manière avec un "awakeFromNib" très long, pour voir s'il attend la fin de l'awakeFromNib avant de continuer la fonction d'appel.
Pas besoin de projet en fait... Un bon petit "while(1);" derrière l'appel de "beginSheetForDirectory" confirme que ça n'attend pas la réponse ; les boutons ne deviennent même pas actif.
Donc c'est le thread principal qui gère tout dans ce cas et qui attend la réponse (même si pour faire ce système d'attente d'événements, il faut plusieurs threads non ? À un niveau supérieur quoi... Hum, non, même pas en fait ; la runloop doit checker les events à chaque passage...)
Donc pour résumer : - Dans ce cas, il n'y a effectivement pas besoin de thread (j'avoue que ça me choque de voir qu'il attend de finir la fonction avant d'attendre la réponse de l'utilisateur ; c'est indigne d'un UNIXÂ ;D) - Les threads sont une bonne solution pour avoir quelque-chose qui se fait en parallèle du thread principal sans le bloquer, et ça aurait pu fonctionner comme ça (je ne dirai pas "dû"Â :P)
Donc en fait, quand on dit "non bloquant" en Cocoa, c'est un mensonge éhonté, car si le NSPanel ne bloque pas la suite de la fonction, la suite de la fonction peut bloquer le NSPanel (cf. l'exemple du "while(1);").
Et par un temps pareil*, il aurait été dommage de rester devant son ordi** et ne pas en profiter pour l'apéro! Santé donc!
*enfin en Gelbique et dans le Nord. Même plus envie de partir dans le Sud à la recherche du Soleil. Et pour une fois qu'on l'a, on le garde, na! **enfin, je dis ça, mais ça fait quelques semaines que je bosse dans le jardin avec le portable.
Il fait beau globalement ici aussi <br />Sauf Dimanche dernier où ça nous a pété sur la gueule :brule:
PS : je viens de comprendre pourquoi vous parliez de threads pour les fonctions "bloquantes" ; c'est parce qu'il bloque le thread principal, donc il n'y a plus rien pour gérer les événements qu'il faut donc gérer dans une autre runLoop ; tout bon ? )
Ici (en Bretagne) c'est pas le grand beau temps mais ça va.
dans 1178042560:
je viens de comprendre pourquoi vous parliez de threads pour les fonctions "bloquantes" ; c'est parce qu'il bloque le thread principal, donc il n'y a plus rien pour gérer les événements qu'il faut donc gérer dans une autre runLoop ; tout bon ? )
Oui, à ceci près qu'en général c'est plutôt l'inverse: On laisse le thread principal faire ce pourquoi il a été lancé (gérer les événements de l'appli) et on détache un autre thread pour le traitement bloquant.
Yep, mais si c'est bloquant c'est pas censé gérer les événements de l'appli, si ? :crackboom:- (il me semble qu'avec du bloquant, on ne peut même plus accéder au menu)
(en fait, je dis "bloquant", mais je parle plutôt de session modale là ...)
Et il y a aussi que les méthodes sont soit synchrones, soit asynchrones (ceci dit pour que ce soit asynchrone il faut en effet plusieurs threads sinon ça n'a pas trop de sens).
Voilà ce que j'essaie de dire depuis tout à l'heure...
Bon je n'ai lu vos échanges qu'en diagonale, qu'est ce que vous avez causé depuis ma dernière visite dites-donc Mais pour dire que je reviens sur ma phrase de dire "pour que ce soit asynchrone il faut avoir plusieurs threads". C'est souvent le cas car c'est plus simple d'avoir un thread pour gérer l'interface par exemple et un autre pour le reste, dans un monde ou le multithreading est la mode. Mais en réalité on peut très bien s'en passer.
Si tu as fait un peu de SDL par exemple, ou je pense aussi à des tutos d'OpenGL où on a à gérer la boucle d'évènements à la main, on voit bien que rien ne nous en empêche.
Bon, c'est carricatural évidemment, enfin surtout très simplifié, mais voici quand même un exemple (avec des fonctions imaginaires, le but est juste d'expliquer le principe) :
int main(int argc, char* argv[])<br />{<br /> char key = 0;<br /> NSPoint mousePos;<br /> int mouseBtn;<br /><br /> // ...<br /><br /> sheet = NULL; // pour l'instant, pas de NSSavePanel d'ouvert<br /><br /> while(1) // boucle évènementielle<br /> {<br /> key = checkForKeyPress(); // vérifie si une touche a été pressée, et la retourne (zéro sinon)<br /> mousePos = checkIfMouseBtnPressed(&mouseBtn) // récupérer les clics souris et leur position<br /><br /> // ... faire des tests selon la touche 'key' tapée si nécessaire ...<br /> <br /> if (askedToSave) // si on a demandé de sauver, afficher la sheet<br /> sheet = [NSSavePanel beginSheet:...]; // etc<br /><br /> if (sheet && (mouseBtn == 1) && [[sheet OKButton] containsPoint: mousePos]) <br /> { // si on avait une sheet active, et qu'on a cliqué sur son bouton "OK"<br /> [sheet closeSheet]; // fermer la sheet pour qu'elle n'apparaisse plus à l'écran<br /> [self didEndSelector:sheet]; // appeler le "didEndSelector"<br /> }<br /><br /> // faire d'autre tests sur la position de la souris, si besoin (correspond à la boucle d'évènement standard)<br /> }<br />}
Voilà , c'est méga simplifié mais c'est pour te montrer qu'on peut très bien en un seul thread afficher puis masquer la sheet de ton NSSavePanel sans que ce soit bloquant. Il suffit de l'inclure dans la boucle évènementielle qui gère les clics souris, les touches clavier, etc.
Or cette boucle existe déjà , et c'est comme ça que fonctionnent les applis Cocoa, ainsi que le système : une boucle qui vérifie régulièrement quelle touche a été tapée ou bien où se trouve la souris, et quel bouton de cette dernière a été cliqué, et ensuite appelle les méthodes qui vont bien (mouseDown:, mouseUp:, keyPressed:, etc) et effectue les actions qui vont bien (afficher le SavePanel, le masquer, etc), sans pour autant être bloquant pour le reste (puisque les touches clavier et évènements souris sont toujours catchés et dispatchés pour autant)
Ici (en Bretagne) c'est pas le grand beau temps mais ça va.
Tiens, en Bretagne toi aussi ?
C'est clair qu'en ce moment c'est moyen car on a le tiercé dans le désordre (pluie, vent, soleil) en ce moment. Résultat, Dimanche on est monté à Cancale pour profiter du soleil sur la plage, et on s'est tapés l'ondée :P (Bon ça s'est calmé ensuite, on a pû profiter de la côte et de la vue en plein vent mais sous le soleil ensuite )
Mais on peut pas trop prévoir le midi si on pourra allumer le barbecue ce soir (d'ailleurs c'est raté pour le coup ) par exemple... Dommage ::)
Bon je n'ai lu vos échanges qu'en diagonale, qu'est ce que vous avez causé depuis ma dernière visite dites-donc Mais pour dire que je reviens sur ma phrase de dire "pour que ce soit asynchrone il faut avoir plusieurs threads". C'est souvent le cas car c'est plus simple d'avoir un thread pour gérer l'interface par exemple et un autre pour le reste, dans un monde ou le multithreading est la mode. Mais en réalité on peut très bien s'en passer.
[...]
Oui-da, cf. conclusions du message #38Â
On peut s'en passer (et l'implémentation actuelle s'en passe !), mais dans ce cas, la suite de la fonction appelante peut bloquer la réception des événements du panel affiché par la fonction appelée dite "non bloquante" (ce qui est assez grave à mon goût, mais bon, puisque tout le monde s'en satisfait, n'en faisons pas tout une histoire )
Pour moi, un système UNIX est censé être multi-thread et multi-process, en user et en abuser ! ;D
Yep, mais si c'est bloquant c'est pas censé gérer les événements de l'appli, si ? :crackboom:- (il me semble qu'avec du bloquant, on ne peut même plus accéder au menu)
Oui, oui, tout a fait, pardon. Restons sur le cas qui nous intéresse ici d'une fenêtre modale.
dans 1178046311:
(en fait, je dis "bloquant", mais je parle plutôt de session modale là ...)
Il est parfois nécessaire de stopper un traitement en cours s'il est conditionné par le retour d'une fenêtre modal (un besoin de confirmer qu'on veut bien continuer a faire telle ou telle chose avec un NSRunAlertPanel par exemple). Tu lances ta fonction, et tu te contentes de tester le retour. Sa simplifie bien la vie même avec un Unix hyper mega threadé.
Au passage, l'AppKit (qui gère tout ce qui touche de près ou de loin aux objets d'IHM) est loin d'être toujours thread-safe. Même NSMovie n'est pas en mesure de s'initialiser convenablement pour lire un flux vidéo ou audio hors du thread principal (cela semble imputable à QuickTime apparemment). Donc méfiance avec les abus et vivement Léopard.
AliGator, t'es Breton aussi!!! Moi, je suis dans la région de Lorient dans le Morbhian (côte d'azur de la Bretagne s'il en est! ;D ).
On peut s'en passer (et l'implémentation actuelle s'en passe !), mais dans ce cas, la suite de la fonction appelante peut bloquer la réception des événements du panel affiché par la fonction appelée dite "non bloquante"
Heu faudra que je la relise au calme demain, celle là , parce que là je suis tout embrouillé...
dans 1178053918:
AliGator, t'es Breton aussi!!! Moi, je suis dans la région de Lorient dans le Morbhian (côte d'azur de la Bretagne s'il en est! ;D ).
Heu non je ne vais pas dire que je suis Breton, en plus je me ferais insulter :P par les Bretons pur souche... Mes parents sont originaires d'Angers et j'y ai passé mes jeunes années jusqu'au Lycée.
Mais j'ai fait mes 5 ans d'étude à Rennes, y bosse depuis bientôt 2 ans, et y vit donc depuis 7 ans (je viens même de déménager pour m'installer dans plus grand).
Donc Breton d'origine, non, mais quand même bien adopté par la Bretagne (et compte y rester) :P
On s'est croisé. J'étais à Rennes (enfin un peu à l'extérieur au Sud du côté de Bruz) pendant 4 ans environ et j'ai déménagé au début de l'année dernière. Une ville très sympa (mais je suis pas objectif car je suis Rennais de naissance... ;D ).
Oups, on dérive sérieusement du sujet là . Mille excuses Tablier.
Y a pas de mal! comme je dis toujours, l'électronique (je suis électronicien) mène à tout, il suffit d'en sortir! je pense que l'informatique aussi! bon, comme on dit chez vous "Kenavo" :P
Réponses
Je sais, et cette partie ne m'intéresse pas... C'est la partie qui consiste à attendre une réponse de l'utilisateur qui m'intéresse particulièrement !
Car cette attente se fait forcément par une boucle qui ne fait quasiment rien tout en monopolisant le thread.
Or pendant cette attente, la fonction qui a appelé "beginSheetWithDirectory" continue, et c'est ça qui me fait dire que l'attente est gérée par un second thread.
(Mais tu as raison, l'affichage peut être géré par le thread principal, panipwoblèm !)
Ton thread principal n'est qu'un gestionnaire d'événement. Il ne monopolise même pas le proc puisqu'il se met en attente.
Sinon, tu avais un élément de réponse ici: http://www.objective-cocoa.org/forum/index.php/topic,2208.msg21388.html#msg21388
OK, comme ça ça peut se concevoir je l'accorde (si on considère que l'attente de la réponse ne se fait qu'après la fin de la fonction d'origine ; même si ça ne me paraà®t pas super logique)... Je vais donc faire un projet qui charge un nib de la même manière avec un "awakeFromNib" très long, pour voir s'il attend la fin de l'awakeFromNib avant de continuer la fonction d'appel.
Un bon petit "while(1);" derrière l'appel de "beginSheetForDirectory" confirme que ça n'attend pas la réponse ; les boutons ne deviennent même pas actif.
Donc c'est le thread principal qui gère tout dans ce cas et qui attend la réponse (même si pour faire ce système d'attente d'événements, il faut plusieurs threads non ? À un niveau supérieur quoi... Hum, non, même pas en fait ; la runloop doit checker les events à chaque passage...)
- Dans ce cas, il n'y a effectivement pas besoin de thread (j'avoue que ça me choque de voir qu'il attend de finir la fonction avant d'attendre la réponse de l'utilisateur ; c'est indigne d'un UNIXÂ ;D)
- Les threads sont une bonne solution pour avoir quelque-chose qui se fait en parallèle du thread principal sans le bloquer, et ça aurait pu fonctionner comme ça (je ne dirai pas "dû"Â :P)
Donc en fait, quand on dit "non bloquant" en Cocoa, c'est un mensonge éhonté, car si le NSPanel ne bloque pas la suite de la fonction, la suite de la fonction peut bloquer le NSPanel (cf. l'exemple du "while(1);").
Paix sur nous tous maintenantÂ
*enfin en Gelbique et dans le Nord. Même plus envie de partir dans le Sud à la recherche du Soleil. Et pour une fois qu'on l'a, on le garde, na!
**enfin, je dis ça, mais ça fait quelques semaines que je bosse dans le jardin avec le portable.
PS : je viens de comprendre pourquoi vous parliez de threads pour les fonctions "bloquantes" ; c'est parce qu'il bloque le thread principal, donc il n'y a plus rien pour gérer les événements qu'il faut donc gérer dans une autre runLoop ; tout bon ? )
Oui, à ceci près qu'en général c'est plutôt l'inverse: On laisse le thread principal faire ce pourquoi il a été lancé (gérer les événements de l'appli) et on détache un autre thread pour le traitement bloquant.
(en fait, je dis "bloquant", mais je parle plutôt de session modale là ...)
Mais pour dire que je reviens sur ma phrase de dire "pour que ce soit asynchrone il faut avoir plusieurs threads".
C'est souvent le cas car c'est plus simple d'avoir un thread pour gérer l'interface par exemple et un autre pour le reste, dans un monde ou le multithreading est la mode. Mais en réalité on peut très bien s'en passer.
Si tu as fait un peu de SDL par exemple, ou je pense aussi à des tutos d'OpenGL où on a à gérer la boucle d'évènements à la main, on voit bien que rien ne nous en empêche.
Bon, c'est carricatural évidemment, enfin surtout très simplifié, mais voici quand même un exemple (avec des fonctions imaginaires, le but est juste d'expliquer le principe) : Voilà , c'est méga simplifié mais c'est pour te montrer qu'on peut très bien en un seul thread afficher puis masquer la sheet de ton NSSavePanel sans que ce soit bloquant. Il suffit de l'inclure dans la boucle évènementielle qui gère les clics souris, les touches clavier, etc.
Or cette boucle existe déjà , et c'est comme ça que fonctionnent les applis Cocoa, ainsi que le système : une boucle qui vérifie régulièrement quelle touche a été tapée ou bien où se trouve la souris, et quel bouton de cette dernière a été cliqué, et ensuite appelle les méthodes qui vont bien (mouseDown:, mouseUp:, keyPressed:, etc) et effectue les actions qui vont bien (afficher le SavePanel, le masquer, etc), sans pour autant être bloquant pour le reste (puisque les touches clavier et évènements souris sont toujours catchés et dispatchés pour autant)
C'est clair qu'en ce moment c'est moyen car on a le tiercé dans le désordre (pluie, vent, soleil) en ce moment.
Résultat, Dimanche on est monté à Cancale pour profiter du soleil sur la plage, et on s'est tapés l'ondée :P
(Bon ça s'est calmé ensuite, on a pû profiter de la côte et de la vue en plein vent mais sous le soleil ensuite )
Mais on peut pas trop prévoir le midi si on pourra allumer le barbecue ce soir (d'ailleurs c'est raté pour le coup ) par exemple... Dommage ::)
Oui-da, cf. conclusions du message #38Â
On peut s'en passer (et l'implémentation actuelle s'en passe !), mais dans ce cas, la suite de la fonction appelante peut bloquer la réception des événements du panel affiché par la fonction appelée dite "non bloquante" (ce qui est assez grave à mon goût, mais bon, puisque tout le monde s'en satisfait, n'en faisons pas tout une histoire )
Pour moi, un système UNIX est censé être multi-thread et multi-process, en user et en abuser ! ;D
Oui, oui, tout a fait, pardon. Restons sur le cas qui nous intéresse ici d'une fenêtre modale.
Il est parfois nécessaire de stopper un traitement en cours s'il est conditionné par le retour d'une fenêtre modal (un besoin de confirmer qu'on veut bien continuer a faire telle ou telle chose avec un NSRunAlertPanel par exemple). Tu lances ta fonction, et tu te contentes de tester le retour. Sa simplifie bien la vie même avec un Unix hyper mega threadé.
Au passage, l'AppKit (qui gère tout ce qui touche de près ou de loin aux objets d'IHM) est loin d'être toujours thread-safe. Même NSMovie n'est pas en mesure de s'initialiser convenablement pour lire un flux vidéo ou audio hors du thread principal (cela semble imputable à QuickTime apparemment). Donc méfiance avec les abus et vivement Léopard.
AliGator, t'es Breton aussi!!! Moi, je suis dans la région de Lorient dans le Morbhian (côte d'azur de la Bretagne s'il en est! ;D ).
Heu non je ne vais pas dire que je suis Breton, en plus je me ferais insulter :P par les Bretons pur souche... Mes parents sont originaires d'Angers et j'y ai passé mes jeunes années jusqu'au Lycée.
Mais j'ai fait mes 5 ans d'étude à Rennes, y bosse depuis bientôt 2 ans, et y vit donc depuis 7 ans (je viens même de déménager pour m'installer dans plus grand).
Donc Breton d'origine, non, mais quand même bien adopté par la Bretagne (et compte y rester) :P
Oups, on dérive sérieusement du sujet là . Mille excuses Tablier.
bon, comme on dit chez vous "Kenavo" :P