Thread Safety et lib standard

a marqué ce sujet comme résolu.

Bonjour, je développe une application multithreading et je peine à trouver des informations sur certains type que je voudrais ThreadSafe.

Je parle notamment des classes Stack et LinkedList (une liste chainée est le plus adaptée). Je tombe à chaque fois sur les Deque (c'est pas le nom complet mais ça deviendrait illisible). S'agit il de la meilleure option ? Cela vaut il le coup sachant qu'on a surtout besoin d'allié simplicité de lecture et rapidité ?

Bonne nuit !

Lu'!

Cette documentation ne suffit pas à ton bonheur ?

Après pour ce qui est de la simplicité, assure toi de transmettre entièrement la propriété de l'objet à ton conteneur ne garde jamais directement ou indirectement un objet qui a été transmis au conteneur.

Le meilleur moyen de faire du code concurrent efficace, c'est de ne pas écrire de code qui agit de manière concurrente.

EDIT : Par contre, une nouvelle incohérence dans le modèle mémoire de Java a été trouvé l'an dernier ou cette année (je crois, je ne connais même pas le nom du papier), je ne sais pas à quel point ça impacte ces conteneurs mais a priori les bugs seraient extrêmement rares à l'exécution, mais pas impossibles. Si quelqu'un peut confirmer/infirmer ?

Je suis tombé dessus, mais j'avoue ne pas être habitué à de la doc. Quand il s'agit de concept que je connais bien et sur lesquels j'ai beaucoup travaillé ça va (typiquement tout le java.util). Mais la programmation concurrente j'en ai fait très peu, uniquement en cours et j'ai un peu de mal a tout saisir.

Très honnêtement, si un bug rare arrive, ce n'est pas bien grave il ne s'agit que d'une application sans enjeu majeur et si ça arrive sur 1 entité qui devrais être supprimé et qui ne l'a pas été, normalement ça n'a pas d'impact si je code bien :p Au pire mon programme s'arrêtera ^^

Quel est le type de concurrence que tu essaies de résoudre ? Comme je te l'ai dit, il faut que tes threads travaillent au maximum sur des données qui leur appartiennent exclusivement.

Et quand je dis exclusivement, c'est même pas une histoire d'exclusion mutuelle sur un accès, c'est que la ressource ne doit vraiment être accessible depuis un seul thread. Sauf, justement ton conteneur thread-safe, et ce n'est pas toi qui l'écris.

Après, il y a des exceptions comme dans le cas de lectures concurrentes, mais ça c'est grosso modo le seul cas qu'on s'autorise et sur lequel il faut être prudent.

En fait je suis en train d'implémenter un ECS (une version plus poussée de Javaquarium) et j'ai donc plusieurs conteneur qui subissent des modifications (ajout et suppression) régulière.

Si tu veux jeter un oeil plus précis dis moi je t'enverrai ce qu'il faut.

Mais j'ai prêter une attention particulière a ne travailler qu'avec du local (en faisant des decorateurs) mais certaines tâches ne peuvent être faite autrement (suppression et ajout typiquement).

Pour être plus précis, j'ai des threads qui viennent se mettre en wait sur une classe et une fois que tout les threads qui doivent se mettre en wait l'ont fait je fait un notify all

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  private static Stack<ComponentSystem> finishedSystems = new Stack<ComponentSystem>();
  private static List<ComponentSystem> systems = SystemsFactory.getSystemsInList();
  
  private static Thread thread;
  
  @Override
  public void run() {
      while(true){
          synchronized (waiter) {
              if(finishedSystems.size() == systems.size()){
                  finishedSystems.clear();
                  waiter.notifyAll();
              }
          }
          try {
              Thread.sleep(SLEEP_TIME);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
  }

  /**
   * ComponentSystem will wait the end of the tick
   * @param system : the system that have finished
   * @throws InterruptedException : done by the wait
   */
  public static void tickEnd(ComponentSystem system) throws InterruptedException{
      synchronized (waiter) {
          finishedSystems.push(system);
          waiter.wait();
      }
  }

Et mes conteneurs ne sont pas thread safe comme tu peux le voir.

Je suis vraiment débutant en programmation concurrentielle, j'ai essayé de rendre les choses le plus indépendantes possible mais il y a peut être mieux et plus performant (typiquement dans le spoiler plutôt qu'un sleep, une combinaison de wait et notify sera plus performante)

Quelles sont les tâches que tu exécutes de manière concurrente ? C'est la mise à jour des bestioles qui se baladent d'en l'Aquarium ? (Si c'est le cas, en vrai la logique d'un jeu c'est pas sensé coûter assez cher pour justifier l'usage de threads, mis à part les IA éventuellement).

Si c'est le cas, tu peux adopter une approche ressemblant à celle utilisée pour un jeu de la vie : conteneur génération N, conteneur génération N+1, puis pour chaque thread : prendre une bestiole et lui faire exécuter sa tâche.

MAIS, une tâche effectuée sur un poisson peut provoquer la mise à jour d'une autre des bestioles. Donc ce n'est pas la bonne solution. Une autre possibilité est de définir un ensemble de tâches à effectuer pour chaque bestiole. Si on doit mettre à jour une des bestioles du jeu, on pousse une tâche dans sa queue de tâches à effectuer. Et on s'assure qu'il n'y a qu'un thread qui peut prendre des tâches dans la queue de ce poisson.

Dans ce fonctionnement, ça marche. Mais c'est complexe et surtout on risque de se taper un bon gros overhead. C'est pour ça que généralement, la logique d'un jeu tourne sur un seul thread parce que la partager entre plusieurs threads c'est tellement chiant que ça coûte la peau de noix pour être fait correctement.

Ce n'est pas vraiment un jeu, mais c'est pas très éloigné non plus.

En fait j'ai des entités sur lesquels je fais des actions et l’intérêt c'est qu'il n'y ai pas un ordre prédéfini des actions et que tout se passe en même temps sur tout. Ca ressemble plus à un ecosystème autonome qu'à un jeu.

Je t'avoue que j'ai du mal a expliquer ce que c'est vraiment sans faire de jolis dessins sur un tableau mais si tu as du temps (et merci pour celui que tu m'as consacré) lis le sujet de l'exercice Javaquarium ça devrait t'éclairer ! :)

Ce n'est pas vraiment un jeu, mais c'est pas très éloigné non plus.

Ricocotam

Le fonctionnement reste globalement très proche d'un jeu. Tu as des entités qui font des choix à chaque pas de temps.

En fait j'ai des entités sur lesquels je fais des actions et l’intérêt c'est qu'il n'y ai pas un ordre prédéfini des actions et que tout se passe en même temps sur tout. Ca ressemble plus à un ecosystème autonome qu'à un jeu.

Ricocotam

Un jeu type RPG c'est profondément un éco-système autonome, c'est juste qu'il y a une entité qui est le joueur (et ça ne fait pas grand différence, au lieu de demander des trucs à une "IA" on demande au clavier/souris ce qu'ils ont vu passer.

La notion de "en même temps" en informatique c'est ultra subjectif. Les entités ne font pas que leur bonhomme de chemin : elles interagissent violemment (à gros coups de vilaines quenottes) entre elles. En l'occurrence, si tu veux pouvoir faire évoluer un tel système de manière parallèle, il faut avoir du parallélisme à grain fin (l'autre solution étant d'associer des mutex à chaque bestioles et dans ce cas, adieu les performances et bon courage pour gérer les dead-locks).

Je t'avoue que j'ai du mal a expliquer ce que c'est vraiment sans faire de jolis dessins sur un tableau mais si tu as du temps (et merci pour celui que tu m'as consacré) lis le sujet de l'exercice Javaquarium ça devrait t'éclairer ! :)

Ricocotam

Déjà lu, je fais partie des personnes qui ont proposé la pratique de l'ECS sur ce sujet ;) .

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