Как правильно выделить память для стека pthread

Я пытаюсь отслеживать использование стека моих потоков. Для этого мне нужно знать адрес стека потоков, и единственный найденный мной способ сделать это — установить стек с помощью pthread_attr_setstack().

В настоящее время я использую mmap для выделения памяти:

   pthread_attr_t ptAttr;
   pthread_t pth;
   pthread_attr_init(&ptAttr);
   void *stack = mmap(NULL, stksize, PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_SHARED, -1, 0);
   pthread_attr_setstack(&ptAttr, stack, stksize);
   pthread_create(&pth,&ptAttr,threadFunc,&info);

Итак, первый вопрос, это хороший способ выделения памяти с помощью mmap? Флаги правильные? Должен ли я использовать malloc вместо этого? Это будет работать на устройстве с низким уровнем ресурсов без виртуальной памяти / памяти подкачки.

Второй вопрос, будет ли эта память освобождаться автоматически, когда поток умирает? Если вы не уверены, есть ли способ узнать, был ли он выпущен?


person barsju    schedule 26.04.2012    source источник


Ответы (1)


Что вы подразумеваете под "монитором"? Если вы просто хотите убедиться, что для стека не тратится слишком много места (что помешает вам иметь много потоков в 32-разрядной системе или системе с низким объемом памяти + подкачка), вы должны просто использовать функцию pthread_attr_setstacksize, а не pthread_attr_setstack. Таким образом, вы не несете ответственности за выделение стека самостоятельно. Вы также можете дополнительно использовать pthread_attr_setguardsize, чтобы обеспечить большую зону защитных страниц в качестве защиты, если вы беспокоитесь, что поток будет выделять более одной страницы за раз в стеке, но имейте в виду, что это займет ваше виртуальное адресное пространство.

Если вы действительно хотите измерить использование стека, pthread_attr_setstack, вероятно, является правильным инструментом, но это совсем не просто. Я бы выделил память с помощью mmap и сделал ее доступной только для чтения. Затем установите обработчик SIGSEGV на mprotect страницу с ошибкой, доступную для записи, увеличьте значение счетчика и выполните возврат. Это даст вам подсчет количества фактических страниц, затронутых потоком. А поскольку обработчик сигнала будет выполняться в потоке, вызвавшем сбой (это гарантировано, поскольку это синхронный сигнал), вы можете сохранить счетчик в локальной переменной хранилища для выполнения подсчета в нескольких потоках.

На самом деле вам может понадобиться сделать последнюю страницу или две доступными для записи перед вызовом pthread_create, поскольку первые попытки записи, вероятно, будут происходить из родительского потока, и вы, вероятно, не хотите, чтобы обработчик сигнала работал там, если вы пытаетесь сохранить результаты в локальном хранилище потока.

Чтобы получить доступ к вашим конкретным вопросам в конце:

  1. Вы не хотите MAP_SHARED. Этот флаг предназначен для памяти, которая будет совместно использоваться процессами. Возможно, в вашем случае это не повредит, но это вводит в заблуждение. Используйте MAP_PRIVATE.

  2. Память не будет освобождена и формально никогда не может быть освобождена. POSIX довольно явно заявляет, что повторное использование или освобождение стека, предоставленного потоку, является неопределенным поведением, поскольку вы не можете надежно определить время жизни (даже после возврата pthread_join концептуально возможно, что поток все еще выполняет свои последние несколько инструкций для выхода и, таким образом, все еще касаясь стека, и вполне возможно, что он будет оставаться в тупике бесконечно долго). Я считаю, что это невозможно в glibc/NPTL из-за того, как они используют сгенерированное ядром событие пробуждения фьютекса при выходе из потока, чтобы сигнализировать pthread_join атомарно с выходом из потока, но NPTL может кэшировать и повторно использовать стеки, которые вы пожертвовали такой теме (поскольку вам все равно не разрешено повторно использовать/освобождать их самостоятельно). Чтобы быть уверенным, вам нужно проверить источник. Таким образом, я бы рекомендовал НЕ вообще использовать pthread_attr_setstack в рабочем коде. Используйте pthread_attr_setstacksize. pthread_attr_setstack следует использовать только для хаков во время разработки, таких как то, что вы можете делать сейчас.

person R.. GitHub STOP HELPING ICE    schedule 26.04.2012
comment
Спасибо за Ваш ответ. Это действительно для разработки, а не для производства, и мы пытаемся измерить максимальное использование стека с течением времени в качестве измерения проблемы стабильности. Мы планируем инициализировать память стека определенным символом или словом, дать потоку поработать какое-то время, а затем проверить, как далеко вниз по стеку мы продвинулись до того, как шаблон будет нарушен, таким образом определяя, какая часть стека заполнена. был использован. И, как вы упомянули, я выделю немного дополнительной памяти и использую mprotect для создания защитной страницы. - person barsju; 26.04.2012
comment
Что касается освобождения памяти, то это не будет большой проблемой, так как те, которые нас интересуют, все равно не будут останавливаться. - person barsju; 26.04.2012
comment
Ваш метод (проверка затертого шаблона), вероятно, работает на практике, и он проще, чем настройка, которую я описал. - person R.. GitHub STOP HELPING ICE; 26.04.2012