Les «benaphores» valent-ils la peine d'être implémentés sur les systèmes d'exploitation modernes?

StackOverflow https://stackoverflow.com/questions/1635416

Question

À l'époque où j'étais programmeur BeOS, je lisais cet article de Benoit Schillings, décrivant comment créer un" benaphore ": une méthode d’utilisation de la variable atomique pour imposer une section critique qui évite la nécessité d’acquérir / libérer un mutex dans le commun contentieux) cas.

Je pensais que c'était plutôt intelligent, et il semble que vous puissiez faire la même chose sur n'importe quelle plate-forme prenant en charge l'incrément / décrémentation atomique.

D'un autre côté, cela ressemble à quelque chose qui pourrait tout aussi bien être inclus dans l'implémentation standard du mutex lui-même ... Dans ce cas, implémenter cette logique dans mon programme serait redondant et ne procurerait aucun avantage.

Est-ce que quelqu'un sait si les API de verrouillage modernes (par exemple, pthread_mutex_lock () / pthread_mutex_unlock ()) utilisent cette astuce en interne? Et si non, pourquoi pas?

Était-ce utile?

La solution

Ce que votre article décrit est couramment utilisé aujourd'hui. Le plus souvent, on l'appelle " Section critique . ;, et il se compose d’une variable verrouillée, d’un groupe d’indicateurs et d’un objet de synchronisation interne (Mutex, si je me souviens bien). En règle générale, dans les scénarios peu conflictuels, la section critique est entièrement exécutée en mode utilisateur, sans impliquer l'objet de synchronisation du noyau. Cela garantit une exécution rapide. Lorsque la contention est élevée, l’objet du noyau est utilisé pour l’attente, ce qui libère la tranche de temps conductrice pour un traitement plus rapide.

De manière générale, l’implémentation de primitives de synchronisation n’a guère de sens à notre époque. Les systèmes d'exploitation proposent une grande variété d'objets de ce type. Ils sont optimisés et testés dans un éventail de scénarios bien plus large que celui qu'un seul programmeur peut imaginer. Il faut littéralement des années pour inventer, mettre en œuvre et tester un bon mécanisme de synchronisation. Cela ne veut pas dire qu’il n’ya aucune valeur à essayer:)

Autres conseils

AbstractQueuedSynchronizer de Java (et son frère AbstractQueuedLongSynchronizer ) fonctionne de la même manière, ou du moins pourrait-il être mis en œuvre de la même manière. Ces types constituent la base de plusieurs primitives de concurrence dans la bibliothèque Java, telles que ReentrantLock et FutureTask .

Cela fonctionne en utilisant un entier atomique pour représenter l’état. Un verrou peut définir la valeur 0 comme non verrouillée et 1 comme verrouillée. Tout thread souhaitant acquérir le verrou tente de changer l'état du verrou de 0 à 1 via une opération de comparaison et de définition atomique; si la tentative échoue, l'état actuel n'est pas 0, ce qui signifie que le verrou appartient à un autre thread.

AbstractQueuedSynchronizer facilite également l'attente des verrous et la notification des conditions en conservant les files d'attente CLH , qui sont des listes chaînées sans verrouillage représentant la ligne. les threads en attente d'acquérir le verrou ou de recevoir une notification via une condition. Cette notification déplace l’un ou l’ensemble des threads en attente de la condition vers l’en-tête de la file d’attente de ceux qui attendent d’acquérir le verrou correspondant.

La plupart de ces machines peut être implémentée sous la forme d'un entier atomique représentant l'état, ainsi que de deux pointeurs atomiques pour chaque file d'attente. La planification actuelle des threads chargés d'inspecter et de modifier la variable d'état (via, par exemple, AbstractQueuedSynchronizer # tryAcquire (int) ) ne relève pas de la portée d'une telle bibliothèque et tombe sur le système hôte. planificateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top