2009-10-29 4 views
0

Je sais que c'est une mauvaise idée! Certainement pour la programmation sûre la pile pour un fil donné devrait être considérée privée à ce fil. Mais POSIX garantit au moins que la totalité de la mémoire d'un thread est partagée et inscriptible par d'autres threads, ce qui signifie que la pile d'un thread peut (en théorie) être écrite par un autre thread. Donc je suis curieux de savoir comment on pourrait faire ça. La seule façon que je puisse penser serait de passer l'adresse d'une variable locale dans le fil B au thread A et A commencer à écrire dans cette zone générale. Mais cela n'émule pas complètement les appels de fonction en C. En particulier, je suis curieux de savoir si on peut dire, avoir thread A dormir tandis que son compteur de programme est mis à la première ligne de certaines fonctions qui prend des paramètres, puis sur le fil B Pousser réellement ces paramètres sur la pile, puis reprendre le fil A et le faire exécuter comme si la fonction était appelée à l'origine dans le fil A avec ces paramètres. Je pense que cela nécessite que le thread B puisse accéder aux registres du thread A sous des conventions d'appel au moins x86, et je ne suis pas sûr que ce soit possible.Comment écrire dans une pile de threads différente en C/C++?

+1

Votre question sur l'écriture dans une pile de threads différente (facile) ou comment contrôler le déroulement d'un thread différent (difficile)? –

+0

Je n'essaie pas de changer le flux d'exécution dans le thread A autre que quand il reprend en pensant qu'il a initialement appelé la fonction avec les paramètres fournis par B.Je ne considère pas, par exemple, comment B peut changer comment le thread A est une boucle ou une branche. –

+0

Peut-être qu'une meilleure approche est simplement d'avoir A appeler la fonction au lieu de B? B peut toujours fournir les paramètres à A, en utilisant n'importe quel mécanisme de communication inter-thread que vous aimez. –

Répondre

1

Il pourrait fonctionner pour passer un pointeur vers une volatile variable locale en fonction foo() dans le thread A à la fonction bar() en fil B, puis laisser modifier fil B son contenu. Mais face à l'optimisation et à la mise en mémoire cache des threads, il n'y a aucun moyen de garantir que cela fonctionnera.

Donc, oui, c'est probablement une mauvaise idée. Pourquoi veux-tu faire cela? Serait sémaphores ou mutex être une meilleure solution?

+0

Qu'est-ce que la "mise en mémoire cache des threads" et pourquoi l'optimisation serait-elle volatile? Le point de volatil est de ne pas être brisé par l'optimisation. –

+0

J'ai lu que plusieurs threads s'exécutant sur plusieurs processeurs (ou processeurs multicœurs) ont des mémoires cache L1 différentes, ce qui peut interférer avec la sémantique 'volatile'. –

0

Il semble que vous essayiez d'implémenter votre propre mutex d'espace utilisateur (rapide), alors pourquoi ne pas explorer simplement en utilisant un futex? Ils can be tricky, mais au moins vous (en dernier recours) avez le noyau pour arbitrer les courses.

Ce qui Loadmaster suggéré pourrait fonctionner, avec deux threads. Plus de deux et ça va devenir très, très bizarre. De plus, je seconde ce qu'il a dit à propos des volatiles qui ne sont pas toujours volatiles.

2

Ok, une façon d'accéder à la pile de threads est d'allouer vous-même la mémoire de la pile et de l'assigner lors de la création du thread. Cela peut être réalisé par appel pthread_attr_setstack().

Les ensembles de codes suivants s'empilent dans la mémoire allouée manuellement (ici malloc) au lieu de l'allouer au système. Plus tard, vous pouvez accéder au pointeur mystack une fois le thread créé. Une utilisation de ce code est, vous pouvez prendre dump de la pile de thread pour prendre son snapshot et plus tard vous pouvez restaurer ce thread.

CODE:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <limits.h>

void *thread(void *arg) { 
     char *ret; 
     printf("thread() entered with argument '%s'\n", (char *)arg); 
     if ((ret = (char*) malloc(20)) == NULL) { 
     perror("malloc() error"); 
     exit(2); 
     } 
     strcpy(ret, "This is a test"); 
     pthread_exit(ret); 
    } 

    int main(void) 
    { 
     pthread_attr_t attr; 
     int    rc; 

     pthread_t thid; 
     void *ret; 

     void *mystack; 
     size_t mystacksize = 2 * PTHREAD_STACK_MIN; 

     if (pthread_attr_init(&attr) == -1) { 
      exit(1); 
     } 

     /* Get a big enough stack and align it on 4K boundary. */ 
     mystack = malloc(PTHREAD_STACK_MIN * 3); 
     if (mystack != NULL) { 
      printf("Using PTHREAD_STACK_MIN to align stackaddr %x.\n", mystack); 
      mystack = (void *)((((long)mystack + (PTHREAD_STACK_MIN - 1))/
           PTHREAD_STACK_MIN) * PTHREAD_STACK_MIN); 
     } else { 
      exit(2); 
     } 

     printf("Setting stackaddr to %x\n", mystack); 
     printf("Setting stacksize to %x\n", mystacksize); 
     rc = pthread_attr_setstack(&attr, mystack, mystacksize); 
     if (rc != 0) { 
      printf("pthread_attr_setstack returned: %d\n", rc); 
      exit(3); 
     } else { 
      printf("Set stackaddr to %x\n", mystack); 
      printf("Set stacksize to %x\n", mystacksize); 
     } 


     if (pthread_create(&thid, &attr, thread, "thread 1") != 0) { 
     exit(1); 
     } 

     if (pthread_join(thid, &ret) != 0) { 
     exit(3); 
     } 

     printf("thread exited with '%s'\n", ret); 
     rc = pthread_attr_destroy(&attr); 
     if (rc != 0) { 
      exit(5); 
     } 

     exit(0); 
    } 

Laissez-nous savoir si cela est ce que vous vouliez. Désolé pour la mauvaise indentation et le style de codage.

+0

Doh, j'ai oublié que lorsque vous créez un autre thread, vous déterminez généralement l'espace utilisé pour sa pile. Cela rend les choses plus simples. Je suis toujours curieux de savoir s'il est possible de manipuler la pile utilisée pour les appels de fonction, ce qui AFAIK nécessite de changer les valeurs de registre d'un thread d'un autre thread. –

Questions connexes