Taille de pile par défaut pour pthreads

24

Si je comprends bien, la taille de pile par défaut pour un pthread sous Linux est 16K. J'obtiens des résultats étranges sur mon installation Ubuntu 64 bits.

$ ulimit -s
8192

Également:

pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &stacksize);
printf("Thread stack size = %d bytes \n", stacksize);

Prints
    Thread stack size = 8388608 bytes

Je suis sûr que la taille de la pile n'est pas "8388608". Qu'est-ce qui ne va pas?

Kamath
la source
7
Je pense 8388608 / 1024 = 8192.
cuonglm
6
Vous pensez à 16k par pile de noyau de thread . Problème totalement distinct de la mémoire de la pile de l'espace utilisateur. les piles de noyau sont minuscules car elles ne peuvent pas être paginées ou allouées paresseusement et doivent être des pages contiguës dans la mémoire physique. elinux.org/Kernel_Small_Stacks . Avoir un nombre extrêmement élevé de threads au total peut être un problème pour i386, où l'espace d'adressage est limité, en particulier avec des piles de 8 Ko par défaut pour 32 bits.
Peter Cordes

Réponses:

21
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

L' stacksizeattribut doit définir la taille de pile minimale (en octets) allouée à la pile de threads créée.

Dans votre exemple, la taille de la pile est définie sur 8388608 octets, ce qui correspond à 8 Mo, comme renvoyé par la commande ulimit -s So that matches.

D'après la pthread_create()description:

Sous Linux / x86-32 , la taille de pile par défaut pour un nouveau thread est de 2 mégaoctets . Sous l'implémentation de thread NPTL, si la limite de ressources logicielles RLIMIT_STACK au moment du démarrage du programme a une valeur autre que "illimitée", alors elle détermine la taille de pile par défaut des nouveaux threads. En utilisant pthread_attr_setstacksize (3), l'attribut de taille de pile peut être explicitement défini dans l'argument attr utilisé pour créer un thread, afin d'obtenir une taille de pile autre que la valeur par défaut.

Ainsi, la taille de la pile de threads peut être définie via la fonction set ci-dessus ou la ulimitpropriété système. Pour le 16k dont vous parlez, il n'est pas clair sur quelle plate-forme vous avez vu cela et / ou si une limite système a été définie pour cela.

Voir la page pthread_create et ici pour quelques exemples intéressants à ce sujet.

fduff
la source
47

En fait, la taille de votre pile virtuelle est de 8388608 octets (8 Mo). Bien sûr, il est naturel de conclure que cela ne peut pas être correct, car c'est une quantité ridiculement grande de mémoire pour chaque thread à consommer pour sa pile alors que 99% du temps, quelques Ko sont probablement tout ce dont ils ont besoin.

La bonne nouvelle est que votre thread utilise uniquement la quantité de mémoire physique dont il a réellement besoin. C'est l'un des pouvoirs magiques que votre système d'exploitation obtient de l'utilisation de l'unité de gestion de la mémoire matérielle (MMU) dans votre processeur. Voici ce qui se passe:

  1. Le système d'exploitation alloue 8 Mo de mémoire virtuelle à votre pile en configurant les tables de pages de la MMU pour votre thread. Cela nécessite très peu de RAM pour contenir uniquement les entrées du tableau des pages.

  2. Lorsque votre thread s'exécute et essaie d'accéder à une adresse virtuelle sur la pile à laquelle aucune page physique n'est encore affectée, une exception matérielle appelée «erreur de page» est déclenchée par la MMU.

  3. Le cœur du processeur répond à l'exception de défaut de page en passant à un mode d'exécution privilégié (qui a sa propre pile) et en appelant la fonction de gestionnaire d'exception de défaut de page à l'intérieur du noyau.

  4. Le noyau alloue une page de RAM physique à cette page de mémoire virtuelle et retourne au thread de l'espace utilisateur.

Le thread de l'espace utilisateur ne voit rien de tout cela. De son point de vue, il utilise simplement la pile comme si la mémoire était toujours présente. Pendant ce temps, la pile s'agrandit (ou non) automatiquement pour répondre aux besoins du thread.

Le MMU est un élément clé du matériel des systèmes informatiques d'aujourd'hui. En particulier, il est responsable de beaucoup de "magie" dans le système, donc je recommande fortement d'en savoir plus sur ce que fait la MMU, et sur la mémoire virtuelle en général. De plus, si votre application est sensible aux performances et traite une quantité importante de données, vous devez comprendre comment fonctionne le TLB (le cache de table des pages de la MMU) et comment vous pouvez restructurer vos données ou vos algorithmes pour maximiser votre taux de réussite TLB.

jtchitty
la source