Comme j'étais moi-même quelque peu confus, je commence par clarifier quelques concepts de la question.
Collection . Je ne vois aucune raison de passer du temps à définir rigoureusement ce que signifie «collecte» alors que nous pouvons simplement demander ce qui se passe pour les structures de données en général. Une structure de données occupe un morceau de mémoire et comporte certaines opérations qui peuvent accéder à cette mémoire et qui peuvent être invoquées par les utilisateurs . Ces utilisateurs peuvent être des processeurs distincts ou simplement des threads différents, cela ne nous concerne pas. Tout ce qui compte, c'est qu'ils puissent exécuter des opérations en parallèle.
Sans verrou . Herlihy et Boss affirment qu'une structure de données est sans verrouillage lorsqu'un utilisateur en panne n'empêche pas d'autres utilisations de la structure de données. Par exemple, imaginez que l'on verse de l'eau sur un processeur qui est en train d'insérer un nœud dans un ensemble trié. Eh bien, si d'autres processeurs tentent plus tard de s'insérer dans cet ensemble trié, ils devraient réussir. ( Modifier: selon cette définition, il est vrai que si une structure de données utilise des verrous, elle n'est pas sans verrouillage, mais il n'est pas vrai que si une structure de données n'utilise pas de verrous, elle est sans verrouillage.)
Avec ces définitions, je pense que Herlihy et Boss disent essentiellement que la réponse est de transformer les régions critiques en transactions.
Mais, demandez-vous, cela a-t-il la même complexité? Je ne suis pas sûr que la question ait un sens. Considérez push(x) { lock(); stack[size++] = x; unlock(); }
. S'agit-il d'une opération à temps constant? Si vous ignorez l'opération de verrouillage et donc les autres utilisateurs, vous pouvez répondre OUI. Si vous ne souhaitez pas ignorer les autres utilisateurs, il n'y a vraiment aucun moyen de dire si le push s'exécutera en temps constant. Si vous montez d'un niveau et voyez comment la pile est utilisée par un algorithme particulier, vous pourrez peut-être dire que la poussée prendra toujours un temps constant (mesuré maintenant en termes de tout ce qui se trouve être l'entrée de votre algorithme parallèle). Mais c'est vraiment une propriété de votre algorithme, il n'est donc pas logique de dire que la poussée est une opération à temps constant.
En résumé, si vous ignorez combien un utilisateur exécutant une opération attend d'autres utilisateurs, l'utilisation de transactions au lieu de régions critiques répond à votre question par l'affirmative. Si vous n'ignorez pas le temps d'attente, vous devez regarder comment la structure de données est utilisée.