Размер стека по умолчанию для pthreads

24

Как я понимаю, размер стека по умолчанию для pthread в Linux составляет 16K. Я получаю странные результаты при моей 64-битной установке Ubuntu.

$ ulimit -s
8192

Также:

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

Prints
    Thread stack size = 8388608 bytes

Я совершенно уверен, что размер стека не "8388608". Что может быть не так?

Kamath
источник
7
Я думаю 8388608 / 1024 = 8192.
cuonglm
6
Вы думаете о 16k стеков ядра потока . Полностью отделить проблему от памяти стека пространства пользователя. Стеки ядра являются крошечными, потому что они не могут быть разбиты на страницы или распределены лениво, и должны быть смежными страницами в физической памяти. elinux.org/Kernel_Small_Stacks . Чрезвычайно большое количество общих потоков может быть проблемой для i386, где адресное пространство ограничено, особенно со стеками 8 КБ по умолчанию для 32-битных.
Питер Кордес

Ответы:

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

stacksizeАтрибут определяет размер минимального стека (в байтах) , выделенный для созданного стека нитей.

В вашем примере размер стека установлен равным 8388608 байтов, что соответствует 8 МБ, что возвращается командой ulimit -s So, что соответствует.

Из pthread_create()описания:

В Linux / x86-32 размер стека по умолчанию для нового потока составляет 2 мегабайта . Согласно реализации многопоточности NPTL, если предел мягкого ресурса RLIMIT_STACK во время запуска программы имеет какое-либо значение, отличное от «unlimited», то он определяет размер стека по умолчанию для новых потоков. Используя pthread_attr_setstacksize (3), атрибут размера стека может быть явно установлен в аргументе attr, используемом для создания потока, чтобы получить размер стека, отличный от значения по умолчанию.

Таким образом, размер стека потока может быть установлен либо с помощью указанной выше функции set, либо через ulimitсистемное свойство. Для 16k, на которые вы ссылаетесь, неясно, на какой платформе вы видели это и / или был ли установлен какой-либо системный лимит для этого.

Смотрите страницу pthread_create и здесь для некоторых интересных примеров по этому вопросу.

fduff
источник
47

На самом деле, размер вашего виртуального стека составляет 8388608 байт (8 МБ). Конечно, естественно сделать вывод, что это не может быть правильно, потому что это невероятно большой объем памяти для каждого потока, который он использует для своего стека, когда в 99% случаев пара КБ, вероятно, - все, что им нужно.

Хорошей новостью является то, что ваш поток использует только тот объем физической памяти, который ему действительно необходим. Это одна из магических возможностей, которые ваша ОС получает от использования аппаратного модуля управления памятью (MMU) в вашем процессоре. Вот что происходит:

  1. Операционная система выделяет 8 МБ виртуальной памяти для вашего стека, настраивая таблицы страниц MMU для вашего потока. Это требует очень мало оперативной памяти для хранения только записей таблицы страниц.

  2. Когда ваш поток запускается и пытается получить доступ к виртуальному адресу в стеке, которому еще не назначена физическая страница, MMU вызывает аппаратное исключение, называемое «сбой страницы».

  3. Ядро ЦП реагирует на исключение ошибки страницы, переключаясь в привилегированный режим выполнения (который имеет свой собственный стек) и вызывая функцию обработчика исключения ошибки страницы внутри ядра.

  4. Ядро выделяет страницу физической памяти этой странице виртуальной памяти и возвращает ее обратно потоку пользовательского пространства.

Поток пользовательского пространства не видит ничего из этой работы. С его точки зрения, он просто использует стек, как если бы память была там все время. Между тем, стек автоматически увеличивается (или не увеличивается) для удовлетворения потребностей потока.

MMU является ключевой частью аппаратного обеспечения современных компьютерных систем. В частности, он несет ответственность за большую часть «волшебства» в системе, поэтому я настоятельно рекомендую узнать больше о том, что делает MMU, и о виртуальной памяти в целом. Кроме того, если ваше приложение чувствительно к производительности и имеет дело со значительным объемом данных, вы должны понимать, как работает TLB (кеш таблицы страниц MMU) и как вы можете реструктурировать свои данные или свои алгоритмы, чтобы максимизировать частоту обращений к TLB.

jtchitty
источник