Code Design, Thread & NSStream

iTomiTom Membre
décembre 2013 modifié dans API AppKit #1
**Bonjour**, J'ai un problème de design avec mon application...

 

Avant de faire une UI, j'ai décidé de faire une 'Command Line' app.

J'ai (main.m) MainThread (Thread 1) attendant toujours pour un Input, quand il en a un il commence un  background Thread (Thread 2) (IFParser.m) parse input.

Jusque là  tout va bien sans aucun problème de mémoire.

 

 2 inputs command possible:

    

    Login 'username'

    Logout 'username'

 

> Typing 'login john' (Thread 1)

> Parsing (Bg Thread 2)

> Login 'john' to the server (Bg Thread 3).

> Thread 2 release

 

Ici, on a 2 threads: Thread 1 (Main) & Thread 3 (NetworkHandler)

 

Maintenant j'ai besoin de communiqué de Thread 2 -> Thread 3 pour logout...

 

Je pensais utiliser NSNotification, (je sais j'ai déjà  faux ici ;))

 

 

> Observe Notification 'Logout-username' from Thread 3

> Send Notification 'Logout-username' from Thread 2

> Thread 2 is release.

> Thread 3 got notify, and stop here

> Thread 3 is release.

 

Thread 3 implement NSStream et gère la connexion, créant des threads pour parsing, reading, writing msg et les release directe après.

 

Je sais que ma façon de faire est mauvaise, c'est difficile de vérifier qu'un User est déjà  connecté, et je ne peux pas envoyer de notification à  tous les thread.

 

Je ne voudrais pas utiliser de Block ou GCD directement mais plutôt NSOperation ou NSThread.

Alors comment dois-je m'y prendre ? N'oubliant pas que mon Thread 3 gère une connexion et qu'il peut y avoir plusieurs Thread 3 correspondants à  chaque Username.

 

Pour moi le main thread doit être dédié à  l'update de l'UI et communiquer avec un second Thread qui va réaliser tout le travail et lancer l'exécution sur le main thread l'update de l'UI. Mais comment réaliser cela simplement ? NSThread ? NSOperation ?

 

Merci beaucoup de m'aider, ma tête est sur le point d'exploser ça fait 2 jours que je me tue sur ce problème...

Réponses

  • MalaMala Membre, Modérateur

    Pour ta communication inter-threads déjà  tu oublies NSNotification car cela ne fonctionne que dans le même thread donc impossible de faire communiquer tes threads ensembles. Il te faut un système de FIFO (First Input First Output): un des threads met des données dans le tuyau et l'autre les récupères en sortie. Tu peux faire ça avec un simple NSMutableArray. Par contre, il faut que l'accès soit thread-safe donc toute lecture/écriture doit se faire avec une sécurité (genre NSLock) pour garantir l'intégrité des données.


     


    Après, j'ai pas trop compris où tu galères.


     


    Dans ton cas, j'aurais tendance à  penser que le plus simple c'est mon Framework Core Unit (voir ma signature).


  • En fait j'ai juste du mal à  comprendre le design pattern d'une application, quel code doit fonctionner dans un autre thread, comment ne jamais bloquer l'UI. Mais là  je pense que m'on problème c'est le Main thread qui ne fait qu'attendre un input. J'ai regardé quelques sample code et je penses enfin avoir compris, je vous dirais demain.


     


    De plus, le fonctionnement de NSStream m'intrigue, une fois que je crée une instance de ma classe Network.h qui gère la création/destruction d'une connexion, qui implémente donc:



    - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)streamEvent

    Imaginons que l'app reçoit un très long message qui met du temps à  être traité dans cette méthode. Est-ce que durant ce temps mon UI sera bloqué ? Je ne dois pas comprendre le fonctionnement de NSRunLoop ?


  • AliGatorAliGator Membre, Modérateur
    La programmation multi-threading est un sujet vaste et complexe à  lui tout seul. Il faut avoir conscience de quelles classes sont thread-safe et lesquelles ne le sont pas, conscience qu'il faut protéger les ressources à  accès concurrent, connaissance d'un peu de théorie sur les Mutex, Semaphores et autres NSLock, ce qu'ils permettent et la conséquence de les utiliser...

    Et de toute façon Apple lui-même recommande dans l'ordre d'utiliser les API concurrentes quand elles sont disponibles (NSURLConnection/NSURLSession par exemple pour des requêtes réseau asynchrones sans avoir à  se soucier de l'aspect multithread pour autant), puis NSOperation, puis GCD, et NSThread voire pthread qu'en tout dernier recours. Car utiliser ces APIs bas niveau, et en particulier les utiliser correctement, surtout lorsqu'il s'agit de partage de ressources et de communication inter-thread, ça met en jeu des concepts que beaucoup de gens ne maà®trisent pas parfaitement, et que même ceux qui les maà®trisent bien peuvent tomber dans certains pièges et dans des Race Conditions un peu tricky à  voir / maà®triser.

    Donc le meilleur conseil c'est de lire le Concurrency Programming Guide d'Apple, et d'utiliser NSOperation ou GCD, mais pas les NSThread car si déjà  tu n'es pas à  l'aise avec les NSThread en temps normal vu l'énoncé de ta question, ça va être bien plus compliqué à  gérer pour toi quand il faudra partager des infos inter-threads.

  • Donc le meilleur conseil c'est de lire le Concurrency Programming Guide d'Apple, et d'utiliser NSOperation ou GCD



    J'approuve totalement. C'est ce que j'ai fait sur le conseil d'Aligator. Ce n'est pas forcément très simple mais ça marche très bien. Je fais marcher un appareil connecté en USB et les données reçues s'affichent simultanément à  la réception.


  • Dans ton exemple d'application je penses que les threads ne vont pas t'apporter grand chose (à  par un complexité accru de développement): 


    - D'une part le parsing d'une ligne de commande ne nécessite pas l'utilisation d'un traitement déporté.


    - D'autre part si tu travaille avec les streams (fichier ou réseau) tu peux aussi très bien le faire dans le thread principal sans bloquer l'utilisateur en tirant avantageusement partie de la RunLoop (que ce soit NS ou CF) et des runloopsource.


     Si l'UI est géré dans le thread principal, ce dernier n'est pas uniquement dédié à  l'UI .


  • Pour moi, le plus simple avant d'utiliser les NSThreads, est de terminer l'application (plus ou moins) avec ce qui est déjà  dispo NSOperation/GCD. Si vraiment elle subit des ralentissements, tu pourrais passer aux NSThreads et assimilés.


  • Merci à  tous, avec de la patiente j'ai trouvée mon chemin à  travers ce brouillard...

    Mais c'est vraiment compliqué le MultiThread... Il me faudra un peu plus d'expérience.


     


    Maintenant je rencontre un problème vieux de 2005 avec NSHost... (je commence un nouveau sujet) http://lists.apple.com/archives/macnetworkprog/2005/Aug/msg00034.html


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