28 votes

Que sont les DO et les DONT multi-threading?

Je demande ma nouvelle connaissance de filetage partout et en faisant beaucoup de surprises

Exemple:

J'ai utilisé les threads pour ajouter des numéros dans un tableau. Et le résultat a été différent à chaque temps. Le problème est que tous mes les threads ont été mise à jour le même variable et n'étaient pas synchronisés.

  • Quels sont certains connus fil des questions?
  • Ce que les soins doivent être prises lors de l'utilisation les threads?
  • Quelles sont les bonnes multithreading ressources.
  • Veuillez fournir des exemples.

sidenote:
(J'ai renommé mon programme thread_add.java de thread_random_number_generator.java:-)

28voto

Martin Liversage Points 43712

Dans un environnement multithreading vous devez prendre soin de synchronisation de sorte que deux threads n'a pas les fringues de l'état, en en effectuant simultanément des modifications. Sinon vous pouvez avoir des conditions de course dans votre code (pour un exemple, voir l' infâme Therac-25 accident.) Vous devez également planifier les threads pour effectuer diverses tâches. Ensuite, vous devez vous assurer que vos paramètres de synchronisation, et de la programmation n'est pas de provoquer un blocage où plusieurs threads en attente pour l'autre indéfiniment.

La synchronisation

Quelque chose d'aussi simple que d'augmenter un compteur exige de synchronisation:

counter += 1;

Assumer cette séquence d'événements:

  • counter est initialisé à 0
  • thread récupère counter de la mémoire vers le processeur (0)
  • changement de contexte
  • thread B récupère counter de la mémoire vers le processeur (0)
  • thread B augmentations counter sur le cpu
  • le fil B réécrit counter de cpu à la mémoire (1)
  • changement de contexte
  • enfiler les augmentations counter sur le cpu
  • fil A écrit counter de cpu à la mémoire (1)

À ce stade, l' counter est de 1, mais les deux fils n'a essayer de l'augmenter. L'accès à ce que le compteur doit être synchronisée par une sorte de mécanisme de verrouillage:

lock (myLock) {
  counter += 1;
}

Un seul thread est autorisé à exécuter le code à l'intérieur du bloc verrouillé. Deux threads s'exécutant ce code peut entraîner dans cette séquence d'événements:

  • compteur est initialisé à 0
  • enfiler Une acquiert myLock
  • changement de contexte
  • le fil B essaie d'acquérir myLock mais a plus qu'à attendre
  • changement de contexte
  • thread récupère counter de la mémoire vers le processeur (0)
  • enfiler les augmentations counter sur le cpu
  • fil A écrit counter de cpu à la mémoire (1)
  • enfiler les versions myLock
  • changement de contexte
  • le fil B acquiert myLock
  • thread B récupère counter de la mémoire vers le processeur (1)
  • thread B augmentations counter sur le cpu
  • le fil B réécrit counter de cpu à la mémoire (2)
  • le fil B communiqués myLock

À ce point - counter 2.

La planification

La planification est une autre forme de synchronisation et vous devez vous utilisez la synchronisation des threads mécanismes, tels que les événements, les sémaphores, de la transmission de message etc. pour démarrer et arrêter les threads. Voici un exemple simplifié en C#:

AutoResetEvent taskEvent = new AutoResetEvent(false);

Task task;

// Called by the main thread.
public void StartTask(Task task) {
  this.task = task;
  // Signal the worker thread to perform the task.
  this.taskEvent.Set();
  // Return and let the task execute on another thread.
}

// Called by the worker thread.
void ThreadProc() {
  while (true) {
    // Wait for the event to become signaled.
    this.taskEvent.WaitOne();
    // Perform the task.
  }
}

Vous remarquerez que l'accès à l' this.task n'est probablement pas synchronisé correctement, que le thread n'est pas en mesure de retourner les résultats au thread principal, et qu'il n'y a aucun moyen de signaler le thread de travail à terminer. Tout cela peut être corrigé dans un exemple plus élaboré.

Impasse

Un exemple courant de blocage, c'est quand vous avez deux serrures, et vous n'êtes pas attention à la façon dont vous acquérir. À un moment vous acquérir lock1 avant lock2:

public void f() {
  lock (lock1) {
    lock (lock2) {
      // Do something
    }
  }
}

À un autre moment vous acquérir lock2 avant lock1:

public void g() {
  lock (lock2) {
    lock (lock1) {
      // Do something else
    }
  }
}

Nous allons voir comment cela peut impasse:

  • enfiler les appels f
  • enfiler Une acquiert lock1
  • changement de contexte
  • le fil B appels g
  • le fil B acquiert lock2
  • le fil B essaie d'acquérir lock1 mais a plus qu'à attendre
  • changement de contexte
  • thread tente d'acquérir lock2 mais a plus qu'à attendre
  • changement de contexte

À ce stade, le thread A et B sont en attente pour l'autre, et sont dans l'impasse.

16voto

Henrico Dolfing Points 300

Il existe deux types de personnes qui n'utilisent pas le multi-threading.

1) Ceux qui ne comprennent pas le concept et ne savent pas comment le programmer. 2) Ceux qui comprennent parfaitement le concept et savent combien il est difficile de bien faire les choses.

13voto

Thomas Danecker Points 3127

Je ferais une déclaration très flagrante:

N'UTILISEZ PAS la mémoire partagée.

UTILISEZ la transmission de messages.

En règle générale, essayez de limiter la quantité d'état partagé et préférez des architectures plus événementielles.

9voto

gbjbaanb Points 31045

Je ne peux pas vous donner des exemples en plus de vous diriger sur Google. Recherche pour l'enfilage bases, fil de synchronisation et vous aurez plus de succès que vous savez.

Le problème de base avec le filetage est que les fils ne savent pas les uns des autres, alors ils seront heureux de la bande de roulement sur chacun des autres orteils, comme 2 personnes qui tentent de passer à travers 1 porte, parfois, ils vont passer si l'une après l'autre, mais parfois, ils vont à la fois essayer d'obtenir à travers à la même heure et sera coincé. Cela est difficile à reproduire, difficile à déboguer, et provoque parfois des problèmes. Si vous avez des threads et de voir "aléatoire" les échecs, c'est probablement le problème.

Si les soins doivent être prises avec des ressources partagées. Si votre ami et vous voulez un café, mais il y a seulement 1 cuillère vous ne pouvez pas l'utiliser dans le même temps, l'un de vous aurez à attendre pour les autres. La technique utilisée pour "synchroniser" cet accès à la cuillère est de verrouillage. Vous assurez-vous d'obtenir un verrou sur une ressource partagée avant de l'utiliser, et laissez-le aller par la suite. Si quelqu'un d'autre a le verrou, vous attendez jusqu'à ce qu'ils le libèrent.

Côté problème vient de ces verrous, parfois vous pouvez avoir un programme qui est complexe, tant que vous obtenez un verrou, faire quelque chose d'autre alors accès à une autre ressource et essayer d'obtenir un verrou pour cela - mais à un autre thread a que 2e de ressources, de sorte que vous vous asseyez et attendez... mais si c'2e thread est en attente de la serrure que vous vous tenez pour la 1ère ressource.. il va s'asseoir et attendre. Et votre application se trouve juste là. Cela s'appelle de blocage, 2 fils, tous deux attendent les uns des autres.

Ces 2 sont la grande majorité des thread questions. La réponse est généralement de verrouillage pour une durée aussi brève que possible, et ne détiennent que 1 verrou à la fois.

7voto

Erik Points 985

Je remarque que vous écrivez en java et que personne d'autre n'a mentionné de livres, donc Java Concurrency In Practice devrait être votre Bible multi-thread.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X