91 votes

Threadsafe et réentrant

Récemment, j'ai posé une question, dont le titre est le suivant "Est-ce que malloc est thread safe ?" et à l'intérieur de ça j'ai demandé, "Est-ce que malloc est ré-entrant ?"

J'avais l'impression que tous les réentrants étaient sûrs pour les fils.

Cette hypothèse est-elle fausse ?

59voto

Georg Schölly Points 63123

Cela dépend de la définition. Par exemple Qt utilise les suivantes :

  • Une fonction thread-safe* peut être appelée simultanément depuis plusieurs threads, même si les invocations utilisent des données partagées, car toutes les références aux données partagées sont sérialisées.

  • A réentrant peut également être appelée simultanément depuis plusieurs threads, mais seulement si chaque invocation utilise ses propres données.

Par conséquent, une Sécurité des fils est toujours réentrante, mais une fonction réentrant n'est pas toujours sécurisée.

Par extension, on dit d'une classe qu'elle est réentrant si ses fonctions membres peuvent être appelées en toute sécurité depuis plusieurs threads, pour autant que chaque thread utilise une instance différente de la classe. La classe est Sécurité des fils si ses fonctions membres peuvent être appelées en toute sécurité depuis plusieurs threads, même si tous les threads utilisent la même instance de la classe.

mais ils mettent aussi en garde :

Note : La terminologie dans le domaine du multithreading n'est pas entièrement normalisée. POSIX utilise des définitions de réentrant et de thread-safe qui sont quelque peu différentes pour ses API C. Lorsque vous utilisez d'autres bibliothèques de classes C++ orientées objet avec Qt, assurez-vous que les définitions sont comprises.

3 votes

Cette définition de réentrant est trop forte.

1 votes

Une fonction est à la fois réentrante et thread-safe si elle n'utilise pas de var globale / statique. Thread - safe : lorsque plusieurs threads exécutent votre fonction en même temps, y a-t-il une course ??? Si vous utilisez une variable globale, utilisez un verrou pour la protéger. Ainsi, elle est thread-safe. réentrant : si un signal se produit pendant l'exécution de votre fonction, et que vous appelez votre fonction dans le signal à nouveau, est-ce sûr ??? dans ce cas, il n'y a pas de threads multiples. Il est préférable que vous n'utilisiez pas de variable statique/globale pour la rendre réentrante, ou comme dans l'exemple 3.

44voto

Tim Post Points 21270

Les fonctions réentrantes ne s'appuient pas sur les variables globales qui sont exposées dans les en-têtes de la bibliothèque C prenez par exemple strtok() contre strtok_r() en C.

Certaines fonctions ont besoin d'un endroit pour stocker un "travail en cours", les fonctions réentrantes vous permettent de spécifier ce pointeur dans le propre stockage du thread, et non dans un global. Étant donné que ce stockage est exclusif à la fonction appelante, il peut être interrompu et les fonctions ré-entrantes peuvent être utilisées. rentré sur (ré-entrants) et puisque dans la plupart des cas, l'exclusion mutuelle au-delà de ce que la fonction implémente n'est pas nécessaire pour que cela fonctionne, ils sont souvent considérés comme étant sans fil . Ce n'est cependant pas garanti par définition.

errno, cependant, est un cas légèrement différent sur les systèmes POSIX (et tend à être l'excentrique dans toute explication de la façon dont tout cela fonctionne) :)

En bref, le réentrant souvent signifie thread safe (comme dans "utilisez la version réentrante de cette fonction si vous utilisez des threads"), mais thread safe ne signifie pas toujours re-entrant (ou l'inverse). Quand vous regardez la thread-safety, Concurrence est ce à quoi vous devez penser. Si vous devez fournir un moyen de verrouillage et d'exclusion mutuelle pour utiliser une fonction, alors la fonction n'est pas intrinsèquement sûre pour les threads.

Mais il n'est pas nécessaire d'examiner toutes les fonctions pour l'une ou l'autre. malloc() n'a pas besoin d'être réentrant, il ne dépend de rien en dehors de la portée du point d'entrée d'un thread donné (et est lui-même thread safe).

Les fonctions qui renvoient des valeurs allouées statiquement sont no thread safe sans l'utilisation d'un mutex, futex, ou autre mécanisme de verrouillage atomique. Pourtant, ils n'ont pas besoin d'être réentrants s'ils ne sont pas interrompus.

c'est-à-dire :

static char *foo(unsigned int flags)
{
  static char ret[2] = { 0 };

  if (flags & FOO_BAR)
    ret[0] = 'c';
  else if (flags & BAR_FOO)
    ret[0] = 'd';
  else
    ret[0] = 'e';

  ret[1] = 'A';

  return ret;
}

Donc, comme vous pouvez le voir, l'utilisation de ce système par plusieurs threads sans une sorte de verrouillage serait un désastre mais il n'a aucun intérêt à être ré-entrant. Vous rencontrerez ce problème lorsque la mémoire allouée dynamiquement sera taboue sur une plateforme embarquée.

Dans la programmation purement fonctionnelle, le réentraînement est souvent n'a pas Implicitement thread safe, cela dépendrait du comportement des fonctions définies ou anonymes passées au point d'entrée de la fonction, de la récursion, etc.

Une meilleure façon d'exprimer la notion de "thread safe" est la suivante sûr pour l'accès simultané qui illustre mieux le besoin.

2 votes

Réentrant ne signifie pas "thread-safe". Les fonctions pures impliquent la sécurité thread.

0 votes

Excellente réponse, Tim. Pour clarifier, j'ai compris de votre "souvent" que thread-safe n'implique pas reentrant, mais aussi reentrant n'implique pas thread-safe. Pourriez-vous trouver un exemple d'une fonction réentrante qui est no thread-safe ?

1 votes

@ Tim Post "En bref, réentrant signifie souvent thread safe (comme dans "utilisez la version réentrante de cette fonction si vous utilisez des threads"), mais thread safe ne signifie pas toujours réentrant." qt dit opposé : "Par conséquent, une fonction thread-safe est toujours réentrante, mais une fonction réentrante n'est pas toujours thread-safe."

9voto

Brian Rasmussen Points 68853

D'autres ont déjà donné des réponses utiles, mais si vous voulez des détails supplémentaires, l'article de wikipedia sur le réentraînement vaut le coup d'œil.

7voto

immibis Points 5859

Tout code ré-entrant est thread-safe. Cependant, tout le code thread-safe n'est pas ré-entrant, par exemple une fonction qui synchronise l'accès à une section critique n'est pas ré-entrante (parce qu'elle ne peut pas être entrée par plusieurs threads) mais elle est thread-safe (parce que l'appeler depuis plusieurs threads ne posera aucun problème).

1voto

stefaanv Points 7326

En complément des réponses précédentes : deux fonctions réentrantes peuvent ne pas être thread-safe si elles manipulent des données partagées sans verrouillage.

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