2011-12-13 5 views
8

Je suis dans une situation où je dois lire un arbre de recherche binaire (BST) dans un gestionnaire de signal (SIGSEGV gestionnaire de signal, qui selon mes connaissances est par base de threads). Le BST peut être modifié par les autres threads de l'application.Lire des données partagées dans un gestionnaire de signal

Maintenant, comme un gestionnaire de signal ne peut pas utiliser des sémaphores, des mutex, etc. et ne peut donc pas accéder aux données partagées, Comment puis-je résoudre ce problème? Notez que mon application est multithread et fonctionne sur un système multicœur.

+5

J'essaierais vraiment, vraiment fort, de penser à un moyen de ne pas lire les données partagées dans ce gestionnaire de signal. – dbeer

+1

Pour souligner le point de @dbeer, dans un gestionnaire de signal, vous ne devriez généralement pas faire quoi que ce soit qui bloque ou soulève d'autres signaux, ou de longues opérations. Un gestionnaire de signal doit être petit, rapide et court. –

+1

Peut-être qu'il me manque quelque chose, mais si seulement les threads de votre programme accèdent à la mémoire partagée (pas d'autres interruptions et exceptions), pourquoi ne pas utiliser un sémaphore (si le bon style est une question différente)? Si un thread accède à la région critique, la bloque, est mis en sommeil par un autre thread, le sémaphore est toujours verrouillé pour l'autre thread, et votre thread initial sera éventuellement programmé pour y accéder à nouveau. Pour des raisons de performances, je ne vois ni danger de corruption de données ni blocage du système. – gnometorule

Répondre

3

En supposant que le SH ne peut pas accéder aux données partagées directement, alors vous pourriez peut-être faire indirectement:

  1. ont une certaine variable globale que seuls les gestionnaires de signaux peuvent écrire, mais peut être lu d'ailleurs (même si seulement dans le même fil).
  2. SH définit le drapeau lorsqu'il est appelé
  3. Les threads interrogent ce drapeau lorsqu'ils ne sont pas en train de modifier le BST; quand la recherche est réglée, ils effectuent le traitement requis par le signal d'origine (en utilisant les synchronisations nécessaires), puis déclenchent un signal différent (comme SIGUSR1) pour indiquer que le traitement est terminé
  4. Le signal SH pour ce signal réinitialise le drapeau

Si vous êtes préoccupé par le chevauchement des SIGSEGV, ajoutez un compteur au mixage pour garder une trace. (Hey, vous venez de construire votre propre sémaphore!)

Le maillon faible ici est évidemment le sondage, mais c'est un début.

+0

Je pensais exactement la même chose :-p! Mais qu'arrivera-t-il quand un thread modifie le BST quand le signal se produit? Ce point est un peu inquiétant. – MetallicPriest

+0

Je pense que ce ne serait pas un problème: le signal sera attrapé, mettre le drapeau et retourner; le thread continuera à modifier le BST, et n'essaiera pas de "gérer" le signal tant qu'il n'aura pas été modifié. En supposant que de telles modifications doivent être atomiques, cela semble être un résultat raisonnable. –

1

Vous pouvez envisager mmap -d'un système de fichiers fuse (dans l'espace utilisateur).

En fait, vous serez plus heureux sur Gnu Hurd qui a un support pour external pagers

Et peut-être votre hack de la lecture d'un arbre de recherche binaire dans votre gestionnaire de signal peut souvent fonctionner dans la pratique, non portably et dans un noyau manière dépendant de la version. Peut-être que la sérialisation de l'accès avec des astuces non portables de bas niveau (par exemple, futexes et atomic gcc builtins) pourrait fonctionner. Lire le code source (spécifique à la machine) de NPTL, c'est-à-dire les routines pthread Linux actuelles, devrait aider.

Il pourrait probablement être le cas que pthread_mutex_lock etc sont en fait utilisables depuis l'intérieur d'un gestionnaire de signal Linux ... (car il ne fait probablement que futex et des instructions atomiques).

+0

J'ai mentionné quelques trucs non portables et Gnu Hurd ... –

3

Je vois deux solutions tout à fait propres:

  1. Linux spécifiques: Créez des signaux de manipulation de fil dédiés. Capturer les signaux en utilisant signalfd(). De cette façon, vous allez gérer les signaux dans un fil régulier, pas n'importe quel gestionnaire limité. Portable: Utilisez également un thread dédié qui dort jusqu'à la réception du signal. Vous pouvez utiliser un canal pour créer une paire de descripteurs de fichier. Le thread peut lire (2) à partir du premier descripteur et dans un gestionnaire de signal, vous pouvez écrire (2) dans le second descripteur. L'utilisation de write() dans un gestionnaire de signal est légale selon POSIX. Lorsque le thread lit quelque chose dans le tuyau, il sait qu'il doit effectuer une action.
Questions connexes