Données critiques et threads

février 2006 modifié dans API AppKit #1
Bonjour,

Je souhaiterais avoir vos avis pour l'accès à  un objet par plusieurs threads. Cet objet (un NSMutableDictionary) est un cache d'images pouvant être demandé plusieurs centaines de fois par seconde. Il est remplit et lu par 0 ou plusieurs threads. Le tout se déroule donc sur quelques secondes.... c'est pour cette raison que j'ai peur de mettre en place un nslock diminuant les performances. Existe t-il d'autres solutions ?

Merci.

Réponses

  • 07:42 modifié #2
    Tu as regardé du côté des objets distribués?

    http://www.objective-cocoa.org/forum/index.php?topic=438.msg4715#msg4715
    Il te suffirait par exemple de mettre un accesseur vers ton dictionnaire depuis l'objet que tu définis comme le rootObject (voire le dico lui même). Je ne sais pas ce que ça donne sur le plan thread-safe ceci dit, mais à  priori c'est fait pour.
  • aranaudaranaud Membre
    07:42 modifié #3
    Et si on ne met rein de spéciale. CEla peut-il entraà®ner un plantage de l'application ?
  • AliGatorAliGator Membre, Modérateur
    07:42 modifié #4
    Je ne pense pas que ça pose un quelconque problème si ce n'est que lu et pas écrit.

    Par exemple si tu écris ton dictionnaire, et après tu commences la session de lectures intensives mais sans écriture.

    Si pendant toute la section critique tu n'as que des lectures, il n'y a pas de soucis.
    Ce n'est que s'il y a des écritures et des lectures en concurrence que là  il faut mettre en place des NSLocks.
  • février 2006 modifié #5
    Oui car c'est un cache, donc il a une taille fixée, donc je peux commencer à  lire un objet qui sera supprimé une fraction de temps après par un autre thread pour un besoin d'ajouts... Je pourrais mettre un retain le temps de faire tu vas me dire mais je ne suis pas sur de la fiabilité non plus...

    En lecture seule ça serait un NSDictionary donc dans ce cas 0 problème.

    En fait pour l'histoire j'ai supprimé ce système de threads, je récupère les images plus rapidement et je n'ai plus besoin de threads mis en place au temps où je n'avais pas la fonction speed carbon... (ne sachant pas faire)

    aranaud, ce n'est pas fiable à  100%... J'avais déjà  un système avec des flags mais par moment l'application restait bloquée (deux threads s'attendant entre eux...)
  • aranaudaranaud Membre
    07:42 modifié #6
    Si on lit en même temps que d'écrire sur la même variable, il y a un gros risque si je comprends bien. Et ceci de façon aléatoire en fonction de l'exécution des threads.
  • AliGatorAliGator Membre, Modérateur
    07:42 modifié #7
    Oui tout à  fait aranaud.
    C'est justement toute la difficulté de ce qu'on appelle la "programmation temps réelle" ou l'utilisation de thread multiples qui se partagent les ressources.

    Et c'est à  ça que servent les mutex ("mutual-exclusive", pour donner accès à  unre ressource de façon exclusive qu'à  un thread à  la fois) ou les sémaphores et autres trucs du genre (NSLock en Cocoa pour implémenter ce genre de choses si j'ai tout suivi).




    En effet avec plusieurs threads le principe c'est que les threads se partagent le temps d'execution, et qu'il se peut très bien par exemple si tu fais une boucle for pour écrire 1000 éléments dans un tableau, qu'en plein milieu de cette boucle d'écriture, le thread soit interrompu par un autre thread qui lui cherchera à  lire dans ce tableau... Il pourra alors très bien commencer à  lire alors que l'autre thread n'a pas fini d'écrire, et lire des données nouvelles (déjà  remplacées) au début et des données anciennes (boucle d'écriture pas encore passée par là ) à  la fin, bref faire un joyeux caffouillage entre les anciennes et les nouvelles données, etc...

    C'est pour cela qu'il faut protéger ses ressources partagées par plusieurs threads à  l'aide de sémaphores ou mutex comme ici.

    Pour te donner une idée, on pourrait très bien utiliser un flag à  3 modes "idle","read","write" qui dit dans quel mode on est et dès qu'on thread veut lire, il faut soit que le flag soit idle -- personne n'utilise la ressources -- soit qu'il soir "read" -- d'autres threads utilisent la ressource, mais que pour la lire pas pour la modifier. Si on veut écrire alors là  il faut qu'il n'y ait qu'un seul thread à  la fois à  écrire pour pas qu'ils se marchent dessus, et personne en train de lire (car on pourrait le perturber) donc que le flag soit en "idle".
    Mais bon en fait c'est pas aussi simple que ça non plus, donc il faut mieux utiliser les classes comme NSLock & co plutôt que des flags maison.


    Et puis il y a aussi le risque de ce qu'on appelle les "deadlocks" aussi, c'est à  dire quand 2 threads se bloquent mutuellement. Par exemple une prise de jetons croisés.
    exemple :
    • Thread 1 : prend le jeton A, accède un peu à  la ressource A, puis prend le jeton B, puis accède à  la ressource B, relâche le jeton B, et relâche le jeton A.
    • Thread 2 : prend le jeton B, accèdes un peu à  la ressource B, puis prend le jeton A, le relâche, puis relâche le jeton B.
    • Si le Thread 1 est interrompu par le thread 2 pendant qu'il accède à  la ressource A, le jeton A aura été pris (mais pas relâché).
    • Là  le thread 2 prend le jeton B (aucun problème), puis arrive au moment où il doit prendre le jeton A... mais il est déjà  pris par le thread 1. donc il dit "ok je me met en attente passive et dès que le jeton est dispo je reprendrai la main".
    • Donc le thread 1 peut reprendre la main, le thread 2 étant en attente... mais le thread 1 arrive au moment où il veut prendre le jeton B... qui est utilisé par le thread 2...
    Bref ils se bloquent mutuellement et ne seront jamais débloqués. C'est ce qu'on appelle un "deadlock", bloquage mutuel de threads. >:)




    Donc finalement comme tu le vois, quand on commence à  partager des ressources entre plusieurs thread, faut faire attention à  plein de petites choses.
    C'est aussi pour ça que dans la doc Apple tu as des mentions "thread-safe" et "not thread-safe" parfois. C'est dans les cas où il y a utilisation de ressources partagées et que les mutex/semaphores ont été implémentés ou pas.
  • aranaudaranaud Membre
    07:42 modifié #8
    Merci à  toi AllGator pour ces explications.  o:)
  • 07:42 modifié #9
    Les données en lecture sont elles toutes "sures". Si je n'utilise que les méthodes d'un NSDictionary sur un NSMutableDictionary, ce dernier devient-il sur ? Logiquement il n'y a risque que sur les données susceptibles de changer ?

    Merci.
  • AliGatorAliGator Membre, Modérateur
    07:42 modifié #10
    Très bonne question, et à  dire vrai je n'en sais rien.

    Je serais fortement tenté en effet de répondre oui, qu'il n'y a aucun risque si tu n'utilise que des objets immutable (enfin que tu te contentes de lectures, quoi).
    A une condition bien sûr c'est de ne pas les modifier (dans le sens releaser ton NSDict et le remplacer par un autre) mais ça va de soi.
    Mais je préfère :
    1) Ne pas dire de conneries (donc mon "oui" est très hésitant, quoi)
    2) Te conseiller de mettre des NSLocks quand même, parce que ça ne coute pas grand grand chose finalement de les implémenter dans tes accesseurs.
Connectez-vous ou Inscrivez-vous pour répondre.