Affichage et calculs dans deux threads différents

iSofTomiSofTom Membre
Bonjour,
Je suis en train de faire une application et je me posais une question:
Pour que l'affichage soit toujours fluide et non fonction du temps que prend les calculs, j'utilise deux threads.
  • Mon thread principal ne fait rien (en tout cas de lui-même)
  • Mon deuxième thread fait des calculs, et quand une vue change il appel la méthode setNeedsDisplay sur le thread principal qui va donc se charger de réafficher.


J'ai testé et ça a l'air de marcher, mais est-ce la bonne méthode?
Est-ce qu'il y a autre chose de mieux à  faire?
merci.

Réponses

  • AliGatorAliGator Membre, Modérateur
    10:51 modifié #2
    Bah non, c'est même l'unique façon de faire, toujours faire les rafraà®chissement d'interface dans le thread principal ;)
    Faut juste faire attention quand tu as plusieurs threads à  ce que tes accès à  tes variables partagées entre tes deux threads (comme la variable contenant le résultat de ton calcul, écrite par le thread qui fait le calcul et lue par le thread principal qui l'affiche) soient bien protégés (donc s'assurer d'y accéder via une @property qui ne soit pas déclarée en nonatomic, ou alors mettre des @synchronized(self) autour des accès de cette variable, etc)
  • iSofTomiSofTom Membre
    10:51 modifié #3
    C'est bien ce que je pensais...
    Une autre question dans ce cas:
    pourquoi l'affichage devrait-il toujours être dans le thread principal? N'est-ce pas possible de faire les calculs dans le principal et l'affichage dans un secondaire ? (c'est juste par curiosité)
  • AliGatorAliGator Membre, Modérateur
    décembre 2009 modifié #4
    Parce que la vie d'une application (que ce soit iPhone ou autre d'ailleurs) est gérée par une RunLoop (une sorte de boucle while qui tourne indéfiniement jusqu'à  ce que le thread ou l'application demande à  quitter), dont les principales étapes sont le dépilage et traitement des événements genre NSPort, le dépilage et l'exécution des appels de méthode mis en attente par [performSelector:... onThread: ...], la vérification des NSTimer qui sont programmés pour exécuter la méthode associée si c'est l'heure qu'ils se déclenchent, le dépilage des événements clavier/souris (ou pour l'iPhone, les TouchEvents) et l'appel des méthodes qui vont bien ensuite pour traiter ces événements (demande à  UIWindow de dispatcher ces events aux bonnes vues ou via la responderChain, etc), ... et enfin la mise à  jour de ce qui est affiché à  l'écran... puis on recommence la boucle.

    Au final, quand tu demandes de dessiner qqch à  l'écran ou changer le texte d'un UILabel, etc... ça ne va pas le dessiner directement et immédiatement à  l'écran. Ca va mémoriser l'événement de dessin, dessiner dans un buffer... et c'est seulement à  la prochaine boucle de rafraà®chissement de l'écran que ce buffer sera effectivement sur ton écran. Seule la RunLoop du MainThread effectue cette gestion de l'affichage.
    Et heureusement sinon ça serait le bordel de devoir mettre des mutex de partout à  chaque opération de dessin pour éviter que deux threads écrivent en même temps dans le buffer de la carte vidéo !!


    [EDIT] Lien vers la doc Apple pour plus d'infos sur le cycle de vie d'une application
  • iSofTomiSofTom Membre
    10:51 modifié #5
    J'avais bien compris le coup des RunLoop mais je pensais que si on en créait une autre dans un autre thread, elle gérerait aussi l'affichage, ce qui (si j'ai bien compris ce que tu as dit) est faux...
    Merci pour ta réponse... 
  • mpergandmpergand Membre
    10:51 modifié #6
    Salut à  tous,

    En fait, on a affaire ici à  l'un des points les plus obscures d'OSX.

    Pour Apple l'AppKit est thread safe sauf exception.
    L'avis des devs sur le web c'est plutôt: l'appKit n'est pas thread safe sauf exception.

    Naturellement les choses évoluent à  chaque révision de l'OS.
    En plus là  on est sur l'iPhone.

    Il se peut même que tout ce que je viens de dire n'a aucun sens.

    Va savoir  :)
  • AliGatorAliGator Membre, Modérateur
    10:51 modifié #7
    Pour encore plus d'infos, la doc et encore la doc : les programming guides sont assez bien fournis pour ceux que ça intéresse :
    - Threads and your User interface
    - Application Kit Framework Thread Safety
  • manu57manu57 Membre
    10:51 modifié #8
    Salut,

    C'est valable sur l'iphone et sur le mac et c'est plutôt clair: Il y a des classes thread safe et d'autres non thread safe dans l'appKit et dans foundation. Donc surtout ne pas généraliser voir ici : (http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html

    Le multithreading est vraiment un truc compliqué à  ne pas utiliser à  la légère. Ca peu marcher et puis t'exploser à  la tronche sans prévenir. Il y a des alternatives (idle notification ou run loop observers). Et si vraiment t'as pas le choix, une approche fire&forget est préferable à  l'usage de lock. Dans ton cas par exemple lorsque les calculs sont finis, tu balances un performSelectorOnMainThread avec tes résultats et tu utilises un nouvel objet dans le thread de calcul. Comme ça à  tout moment seul un unique thread utilise la donnée et tout ça sans lock.

    Manu
Connectez-vous ou Inscrivez-vous pour répondre.