6
votes

Est-il possible de mettre en œuvre des primitives de simultanéité Linux implémenant qui donnent une meilleure isolation que les threads, mais des performances comparables?

Considérez une application suivante: Un serveur de recherche Web qu'au démarrage crée un index de pages Web de grande mémoire basé sur les données lues à partir du disque. Une fois initialisé, l'indice en mémoire ne peut pas être modifié et plusieurs threads sont démarrés pour servir les requêtes utilisateur. Supposons que le serveur est compilé au code natif et utilise des threads OS.

Maintenant, le modèle de threading ne donne aucun isolement entre les filets. Un fil de buggy ou tout code de sécurité non du fil peut corrompre l'index ou la mémoire corrompue qui a été allouée et appartient logiquement à un autre thread. De tels problèmes sont difficiles à détecter et à déboguer.

théoriquement, Linux permet d'appliquer un meilleur isolement. Une fois que l'index est initialisé, la mémoire qu'il occupe peut être marquée uniquement. Les threads peuvent être remplacés par des processus partageant l'index (mémoire partagée), mais autres que ceux-ci ont des tas distincts et ne peuvent pas vous corrompre mutuellement. Les opérations illégales sont automatiquement détectées par le matériel et le système d'exploitation. Aucun mutex ou autres primitives de synchronisation n'est nécessaire. Les races de données associées à la mémoire sont complètement éliminées.

est un tel modèle réalisable dans la pratique? Êtes-vous au courant de toute demande de vie réelle qui font de telles choses? Ou peut-être qu'il y a des difficultés fondamentales qui rendent un tel modèle impraticable? Pensez-vous que cette approche introduirait une surcharge de performance par rapport aux threads traditionnels? Théoriquement, la mémoire utilisée est la même, mais existe-t-il des problèmes liés à la mise en œuvre qui feraient plus de choses plus lentes?


3 commentaires

Il y a certainement une application qui utilise le MMAP pour marquer divers espaces de mémoire en lecture seule. Cependant, cela est typiquement pour des raisons de performance et non pour la protection contre le code de buggy.


Bien que je ne veux certainement pas commencer une guerre religieuse, mais passer à l'utilisation d'une langue (telle que Java) qui prend en charge des types vraiment immuables résoudrait beaucoup de problèmes avec des "threads de buggy" que "Mémoire corrompue".


La corruption de la mémoire dans les programmes multi-threading se produit non seulement lorsque le thread écrit à un emplacement aléatoire en mémoire (telles erreurs sont relativement faciles à éviter et à détecter), mais également lorsque le thread obtient une référence valide à un objet qui n'est pas sûr et qui est utilisé. par un autre fil. De telles erreurs sont beaucoup plus difficiles à prévenir et à détecter et peuvent se produire dans tout programme multi-threading, quelle que soit leur langue.


3 Réponses :


0
votes

Je pense que vous pourriez trouver memcached intéressant. De plus, vous pouvez créer une mémoire partagée et l'ouvrir uniquement en lecture seule, puis créez vos discussions. Cela ne devrait pas causer de beaucoup de dégradation de performances.


0 commentaires

1
votes

Vous pouvez utiliser mprotect () pour rendre votre index lecture seule. Sur un système 64 bits, vous pouvez mapper la mémoire locale pour chaque fil à une adresse aléatoire (voir Cet article Wikipedia sur Adresse Space Randomization ) qui rend les chances de corruption de mémoire d'un fil touchant une autre petite taille astronomique (et bien sûr toute corruption qui manque complètement la mémoire mappée provoquera un segfault). Évidemment, vous aurez besoin d'avoir des tas différents pour chaque fil.


4 commentaires

Les threads peuvent-ils avoir des tas différents, ou un tas différentiellement distingue-t-il des threads des processus?


Le tas est juste où malloc obtient sa mémoire. Pour donner différents threads différents, des tas, il suffit de demander à chaque fil d'une piscine différente (à l'aide de données spécifiques à thread). Vous avez juste besoin de la bonne bibliothèque Malloc avec les bonnes options.


Le problème est que l'idée de randomisation du tas n'empêcherait qu'une seule classe de bogues - la corruption de la mémoire en raison de l'écriture des emplacements aléatoires. Comme je l'ai écrit dans d'autres commentaires, ces bugs sont relativement plus faciles à prévenir et à détecter. Le problème plus gros concerne les races de données que l'isolation complète éliminerait complètement. Disons qu'un fil appelle une fonction qui renvoie un pointeur sur un objet statique sans fil non thread. Si un autre thread appelle la même fonction, vous avez une course de données, et cela n'aide pas que le pointeur retourné est randomisé. Le pointeur n'a pas été deviné qu'il a été obtenu via un appel valide.


@JANWROBEL: Je n'ai pas compris à votre question que vous vouliez éviter de devoir écrire du code de sécurité du fil.



4
votes

La solution évidente est de ne pas utiliser de threads du tout. Utilisez des processus distincts. Étant donné que chaque processus a beaucoup en commun avec le code et les structures libéonnoises, la création de données réadonnées est triviale: format-le si nécessaire pour une utilisation en mémoire dans un fichier et caraper le fichier sur la mémoire.

Utilisation de ce système, seules les données variables par processus seraient indépendantes. Le code serait partagé et des données initialisées statiquement seront partagées jusqu'à ce qu'elle soit écrite. Si un processus se froasse, il y a une incidence nulle sur d'autres processus. Pas de problèmes de concurrence du tout.


0 commentaires