2013-07-02 2 views
2

Я пишу многопоточную среду в c, используя setjmp() и longjmp() для переключения между потоками.выделение памяти стека

Я не уверен, как было бы лучше выделить пространство стека для каждого потока. Это должно выполняться динамически в средах с большими потоками, но я не думаю о способе отслеживания того, сколько стека используется потоками, чтобы изменить выделенную сумму.

Я мог бы предварительно выделить статический объем пространства между секциями стека, как это:

void call_with_cushion (void) { 
    char space[1000]; 
    space[999] = 1; /* Do not optimize array out of existence */ 
    child(); 
} 

(фрагмент кода из википедии http://en.wikipedia.org/wiki/Setjmp.h)

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

Благодаря

+0

Обычно вызов «CreateThread» или любой другой вызов выделяет пространство стека с использованием некоторой функции ядра «kmalloc» и предварительно загружает его соответствующим образом, чтобы поток можно запустить с помощью прерывания-возврата, как если бы он был запущен раньше и были выгружены. –

+0

Я подозреваю, что ты на своем пути. –

+1

Это может быть правдой, но буквально любой совет приветствуется, просто не топтайте меня, когда вы прыгаете с высокой лошади ... – jayjay

ответ

3

Как правило, максимальный размер пространства стека, назначенного потоку, фиксируется при создании потока, и если поток превышает это ограничение, результатом является неопределенное поведение - нет возможности увеличить пространство стека за пределами этого предела , Если вам повезет, переполнение стека приведет к некоторому исключению или сигналу переполнения стека (в зависимости от ОС и реализации потоков), но нет никакой гарантии.

Если вы пытаетесь реализовать свою собственную библиотеку потоков, в идеале вы хотите выделить большое количество адресного пространства для стека каждого потока и настроить систему VM для распределения памяти в этом пространстве по требованию, и ловушка, когда пространство заполнено. Это то, что делают большинство библиотек потоков на уровне OS (например, pthreads или win32 threads), но детали управления VM сложны.

Если вы не хотите возиться с материалами виртуальной машины, вы можете выделить больше, чем вы думаете, когда вам понадобится блок в куче для каждого стека потоков, а затем дополнительно запрограммировать указатель стека в вашем коде на посмотрите, будет ли он близок к заполнению (используя больше места, чем вы считали нужным) и ловушка/прерывание, если это так. В зависимости от вашего компилятора может быть предусмотрена возможность автоматически генерировать проверки переполнения стека в каждой функции, которую вы можете использовать.

Код на странице wikipedia - это очень хак - это может сработать, но не делает никаких проверок, чтобы обеспечить достаточное количество стеков и зависит от того, компилятор не делает что-то нечетное с неопределенным поведением, которое будет (например, оптимизируйте неиспользуемую стеквую панель space, что он может сделать даже с заданием).

+0

Спасибо, миллион. Это интересно, я бы подумал, что было бы выделено пространство с переменной величиной, но если это так, то ... Если кто-то встретит это позже; Someones внедрили mt env для AVR здесь: http://think.ow2.org/pdf/AVRMultithreading.pdf, используя стек фиксированного размера для каждого задания. Их код может оказаться полезным или поучительным. Еще раз спасибо! – jayjay

0

Переключение задач с помощью манипуляций стьки часто довольно легко, но setjmp/longjmp не являются адекватными средствами для целей, если Вы не можете манипулировать внутренние структуры jmp_buff. Моментный код выходит из контекста, в котором выполняется setjmp, созданный таким образом jmp_buff становится недействительным, и любая попытка сделать что-либо с ним вызовет Undefined Behavior, и это будет верно, даже если вы надеетесь, что ничего не мешает области стека, где был выполнен setjmp.

Изучите правила ABI (Application Binary Interface) для используемого процессора и изучите достаточный язык ассемблера для выполнения некоторых основных операций с регистрами. Вам, вероятно, не понадобится более 1-2 десятков строк кода сборки, но вам, скорее всего, понадобятся некоторые. Это будет особенно актуально, если вы используете какую-либо инфраструктуру обработки исключений.

+0

Вы очень правы. Я понимаю, что я вхожу в «неопределенное поведение», но согласно тому, что я прочитал, большинство реализаций longjmp() оставляют область действия, из которой они были неповрежденными. Даже если бы я сделал это на ассемблере, у меня все равно была бы проблема с распределением памяти. – jayjay

+0

@jayjay: Возможно, что некоторые реализации 'setjmp' /' longjmp' могут работать, но если вы не изучите и не поймете точно, что они делают, вы не будете знать, что время бомбит; даже если вы изучите их, вы не будете знать, будут ли будущие версии всегда работать одинаково. Всякий раз, когда я делал совместные переключатели задач, я всегда клал стеки всех «лишних» задач в области памяти, которые я выделил, особенно для их хранения. Использование стека не кажется правильным. – supercat

+0

спасибо, похоже, что это путь, я, вероятно, собираюсь спуститься по ассемблерному маршруту. Еще раз спасибо за ваш вклад! – jayjay

Смежные вопросы