Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Boost thread - ограниченное количество потоков?
Форум на CrossPlatform.RU > Библиотеки > boost
Iron Bug
добрый день всем.
вот, может, кто сталкивался с подобной проблемой:
использую библиотеку thread boost'а для кроссплатформенного программирования. до недавего времени всё было замечательно, но тут возникло одно неприятное открытие:
оказалось, что буст почему-то ограничивает возможное количество потоков. а именно: после создания какого-то числа работающих потоков создание очередного потока проваливается с исключением boost::thread_resource_error и до уменьшения количества работающих потоков создание нового потока невозможно (каждый раз выпадает это исключение). причём это максимальное число потоков не зависит от реальных ресурсов системы, либо зависимость мне непонятна.
для проверки была написана маленькая программа - генератор потоков. потоки просто создаются, спят какое-то время, потом завершаются. потоки пустые, мелкие - то есть, памяти теоретически должно хватать. при этом задавалось разное время жизни потоков и разное количество потоков. результаты по подсчёту количества потоков всегда одинаковы, независимо от времени жизни каждого потока. это число каким-то загадочным образом зависит от машины, но, по видимому, не зависит от количества свободной памяти процесса и системы.
из опытов получилась такая странная картина: дома стоит машина под линюксом, 4 гектара памяти, своп вообще не используется - опытным путём получен предел в 382 потока, на работе машина под вендой, 1 гектар памяти, предел - 2024 потока. увеличение-уменьшение количества других процессов в системе никак не влияет.
откуда берутся такие странные цифры? может, есть возможность определить каким-то образом, как распределять ресурсы, чтобы потоков было больше? по работе необходима возможность одновоеменного выполнения очень большого и заранее неопределённого количества потоков в риал-тайме (пул потоков как бы не подходит по замыслу задачи). непонятно, откуда исходит это ограничение и как с ним бороться (если это вообще возможно).
ViGOur
Все правильно, это ограничение потоков, для винды это выставляется в реестре.
Цитата
Какие существуют ограничения на количество потоков в программе?
Разумно предположить, что количество потоков в процессе ограничено ресурсами самого процесса, а так же ресурсами ядра операционной системы.

ПРИМЕЧАНИЕ
Все сказанное ниже справедливо для линейки Windows NT/2000/XP.

Один из основных ресурсов ядра операционной системы, потребляемый при создании потока, это невыгружаемая памяти (non-paged memory) ядра. Создание одного потока требует около 12 килобайт невыгружаемой памяти. Ограничения на размер пула невыгружаемой памяти устанавливается в следующем ключе системного реестра:

HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management

параметрами NonPagedPoolQuota и NonPagedPoolSize. Их значение по умолчанию равно нулю, что отдает управление этими значениями в руки операционной системы.

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

Как известно, каждому процессу выделяется адресное пространство в четыре гигабайта, но под свои нужды процесс может употребить только первые два гигабайта. Собственно из этих двух гигабайт и выделяется память под стек для вновь создаваемого потока. Размер стека определяется двумя факторами - параметром /STACK линковщика и параметром dwStackSize функции CreateThread.

Размер стека, заданный параметром dwStackSize, не может быть меньше, чем указано в параметре /STACK линковщика и по умолчанию равен ему. Размер стека, используемый линковщиком по умолчанию равен одному мегабайту. Таким образом максимальное количество потоков, которые можно создать при всех параметрах заданных по умолчанию, равняется примерно 2035. По достижении этого предела функция CreateThread начинает возвращать ошибку ERROR_NOT_ENOUGH_MEMORY, что является истинной правдой - если умножить количество потоков на размер стека по умолчанию, то как раз получается примерно два гигабайта - размер адресного пространства отданный процессу на карманные расходы.

Обойти это ограничение можно указав меньший размер стека параметром /STACK линковщика или в Project Settings (Link/Output/Stack Allocations/Reserve) в Microsoft Visual C++. Размер стека указывается в байтах. Меняя это значение надо быть осторожным ввиду того, что стек используется не только для хранения адресов возврата функций и передачи параметров, но и для хранения локальных переменных. Однако это тема отдельного разговора.


Для линукса также можно настроить это дело, но как не знаю.
Iron Bug
да сомневаюсь я, что это ограничение по памяти. в моих опытах все ресурсы процесса по пику использования памяти были не больше 60 метров, судя по показаниям диспетчера задач... то есть, до 4 гигов как до луны! можно, кстати, при этом динамически выделять массивы - никаких ошибок не происходит.
у меня подозрение, что тут какая-то хитрость в самом бусте... может, дефайны какие-то надо выставлять ему, чтобы юзал больше ресурсов или что-то подобное. но в документации ничего нет про это.


со стеком в венде настройки попробую поковырять.
результаты сообщу.
Litkevich Yuriy
Цитата(Iron Bug @ 6.2.2009, 14:43) *
что это ограничение по памяти.
я где-то напарывался на обсуждение про ограничение числа потоков, речь шла не о Бусте, но вывод был такой: Есть умалчиваемые настройки ОСи (и линя и виндовоза), которые не позволяют одному экземпляру приложения полдить потоки больше определенного потолка.

Так что я думаю ViGOur, правильную статью показал.
ViGOur
Цитата, которую я привел справедлива для Win32 Api и его CreateThread и прочего отстраненно от boost'a. Так что boost тут не причем. :)

Все зависит от опреционки и ее настроек.
Iron Bug
пока что происходят странные вещи: при УВЕЛИЧЕНИИ размера стека (под вендой) максимальное количество потоков.... УМЕНЬШАЕТСЯ!!! причём пропорционально: в два раза увеличиваю стек - в два раза меньше потоков можно запустить одновременно, в два раза уменьшаю - в два раза больше потоков можно удачно запустить...
вот так... наблюдаю и думаю.... понять сего явления пока не могу :) как математик, могу теоретически предположить, что при уменьшении размера стека до нуля количество потоков приблизится к идеально неограниченному :D
Litkevich Yuriy
Цитата(Iron Bug @ 6.2.2009, 14:56) *
могу теоретически предположить, что при уменьшении размера стека до нуля количество потоков приблизится к идеально неограниченному
:lol:
Iron Bug
дык вот не смешно совсем. пока в песочнице копошишся - всё отлично. а как начинаешь вылазить за пределы обычного десктопного софта - так сразу обнаруживаются всякие тонкости, которые нигде не описаны в документации, либо описаны крайне поверхностно и туманно.

пока что результаты экспериментов в венде:
1. размер стека (параметр линковки) влияет на количество потоков в обратной пропорции. это мне теперь стало понятно: на каждый поток выделяется стек из пула. соответственно, меньше стек - больше потоков. но вот уменьшать размер стека как бы не очень хотелось бы... не то, чтобы дочерние потоки какие-то монстрообразные вглубь и вширь... они, как правило, очень простые и часто даже линейные, но всё же стек есть стек.
2. размер кучи (параметр линковки) не влияет никак
3. размер NonPagedPoolQuota в реестре (вроде как у майкрософта написано, что это есть пул для потока), поставленный в максимум=128 (это число было взято с сайта майкрософта), после перезагрузки машины не дал никакого результата. думаю, общий NonPagedPoolSize (суммарный пул для системы) менять не имеет смысла - ведь остальные приложения жрут и поболе памяти и в сумме при высокой нагрузке на систему венда вполне нормально использует всю память. у меня вообще нет подозрений на нехватку пула. какие-то 60 метров - это вообще пустяки для системы.

очевидно, система просто рассчитывает максимальное количество потоков исходя из размера стека и возможности адресации 2 гигов на процесс и на этом всё, и ничего тут не изменить...

про линюкс пока туман. буду копать ещё и ставить эксперименты дома.
ViGOur
Как решишь проблему опиши как решил, а то больно интересная тема! :)
some_x
Цитата(Iron Bug @ 6.2.2009, 14:23) *
добрый день всем.
вот, может, кто сталкивался с подобной проблемой:

Я провёл исследования на линуксе используя pthread(увеорен boost.thread на линухе реализован через него). Действительно со стандартным размером стэка(а это, как выяснилось 8-мь мегабайт) можно создать где-ьл 382 нити. При стэке более 2.5 гигабайт не удаётся создать ни одной нити(ошибка ENOMEM). Проверил на машине с 2 гигабайтами памяти и с одним, граница не изменилась. При указании размера стека 4096*1024*1024 байт получил ошибку: некорректное значение стэка. При стэке размером в 1 гигабайт удавалось создать не более двух нитей. Таким образом можно сделать вывод что в линуксе(если используется nptl) суммарный размер стэка создаваемых нитей должен быть не больше 2.5 гигабайт(примерно), хотя возможно какие-то системные твики могут это изменить.
ViGOur
Цитата(some_x @ 22.2.2009, 0:00) *
хотя возможно какие-то системные твики могут это изменить.
Я тоже слышал, что *nix'ах где-то это настраивается, а вот где пока не знаю.
Andrew Selivanov
#include <stdio.h>
#include <windows.h>

DWORD CALLBACK ThreadProc(void*)
{
Sleep(INFINITE);
return 0;
}

int __cdecl main(int argc, const char* argv[])
{
int i;
for (i = 0; i < 100000; i++) {
  DWORD id;
  //HANDLE h = CreateThread(NULL, 0, ThreadProc, NULL, 0, &id);
    HANDLE h = CreateThread(NULL, 4096, ThreadProc, NULL,
               STACK_SIZE_PARAM_IS_A_RESERVATION, &id);
  if (!h) break;
  CloseHandle(h);
}
printf("Created %d threads\n", i);
return 0;
}


У меня 8643 потока...
Взято отсюда: http://blogs.msdn.com/oldnewthing/archive/.../29/444912.aspx

А нахрена столько...?
Iron Bug
Цитата(Andrew Selivanov @ 20.3.2009, 16:38) *
А нахрена столько...?

нуу... 8 тыщ, может, и не надо, но больше 2000 иногда может и понадобиться.
просто я работаю в конторе, где разрабатывают железяки. железяки очень сложные, реально постоянно в разработке куча девайсов, которые надо тестировать - это моя работа. и вот у меня задумка сделать нечто типа скриптового языка для создания тестов. так как иначе это бесконечное писание тестового софта, а времени на серьёзное тестирование, как правило, очень мало. в одной машине к шине могут быть подключены тысячи девайсов - обычно лучше иметь на каждый девайс свой скрипт обработки, и, соответственно, свой отдельный поток... отсюда и такие странные требования. ну а в общем, всё равно полезно знать, что в системе можно реализовать, а что - нет.
сейчас кое-как у меня написан первый прототип скриптового монстра и он даже реально работает, но - увы - неоптимально. я думаю капитально переделать существующую реализацию. поэтому уже два месяца ночами не сплю, думаю, как сделать быструю и надёжную универсальную систему для тестирования. а кроссплатформа - это, понятное дело, ради линюкса затеяно. под вендой это почти гиблое дело. однако пока тестирование идёт под вендой. если я напишу пару дровов под линь для общения с шиной - то можно будет без гемора всё тестировать под линём на одной корзине, что существенно упростит жизнь :) вот и ковыряюсь помаленьку...
Andrew Selivanov
Ааа.. стало яснее, но картину в целом всё равно представить сложно :)
Я обычно всё что связано с тестированием или срочно проверить итп ваяю на Perl-e. Очень удобно.

<тупые советы>
Кстати лучше ночью спать. Еще банальность - совершенство недостижимо ;) Еще банальность - чем проще тем лучше.
</тупые советы>

На самом деле для внутренностей винды наиболее авторитетное и объемное издание это Сломон/Руссинович "Internals..." Хотя искать там что-то сложновато да и есть не всё. Но тем не менее.
Там довольно хорошо раскрыта тема потоков.

И ещё я тут подумал - есть ли вообще смысл в многопоточной модели в твоём случае? Ведь реальных ядер всего (два, четыре, восемь) а потоков - куча. Будет много переключений контекста. Не проще ли взять нечто вроде Reactor-а ( http://www.cs.wustl.edu/~schmidt/PDF/reactor-rules.pdf ) и контролировать взаимодействие самому..?
Tonal
Ежели железки тестируются независимо, то действительно почему бы не взять какой-нибудь нормальный скриптовый язык, Python, например.
И запускать по процессу на каждую железячку?
Думаю тот же linux 2000 python процессов выдержит без труда. :)

Ежели что-то более сложное - можно erlang посмотреть - вроде самое оно. :)
Iron Bug
To Andrew Selivanov:
Руссинович у меня есть, но действительно довольно мутная книжка, сложно там что-то найти. Рихтер тоже ничего, гораздо более читабельно. Собственно, у меня вопросов-то почти не возникает, я под венду очень давно пишу. Про потоки в венде я и так знаю всё. Я и дрова для железа под неё писала, и сервисы, и всякие приблуды для юзеров, и всё, что только можно... Ну, архитектура у неё... эээ... КХМ... короче говоря, венда и есть венда! У компании пока по некоторым причинам нет планов переходить на линюкс, хотя давно пора уже! Мешает куча наработок и боязнь перехода. Собственно, планы всегда горят и особо времени нет, а кадров вечно не хватает... И вот сейчас у меня есть идея перейти на кроссплатформу и окончательно избавиться от мелкософтовских библиотек, что я уже успешно сделала в первом приближении. Но, как всегда бывает, сначала система была простой и логичной, но потом по требованиям юзеров обрастала всё новыми и новыми фичами, которые надо было городить срочно и которые всё хуже и хуже увязывались с изначально поставленными задачами... И вот программа превратилась в монстра, обвешанного костылями и стала ненадёжно работать. Поэтому я сейчас вот измышляю универсальную и стройную систему, чтобы учесть те требования, которые на данный момент существуют и, по возможности, предусмотреть возможность для безболезненной модификации при необходимости внесения новых фич. Более того, я замышляю линюксовый переворот хотя бы в области тестирования. Хочу попробовать написать пару дров и полностью протестировать работу машин под линём. Естессно, с демонстрацией преимуществ линюкса начальству! :) Я знаю, что я фанат, но тут ничего не поделать.
To Tonal:
Насчёт скриптов... Железки не независимы! Они как раз представляют собой единый очень сложный механизм. И процессы и потоки активно взаимодействуют в риал-тайме... И ещё юзер вмешивается до кучи. И надо проверять что все ответы от девайсов приходят, и чтобы юзера куда-нибудь не зажевало случайно, и чтобы железяки не запороли друг друга и ещё команды подавать, чтобы всё это бодро шевелилось :) Скрипты - хорошая вещь для мелких задач. А у меня задачи объёмистые и надо ещё юзерский интерфейс городить. Тестирую, естественно, не я, а те люди, которые занимаются разработкой механики. Так что нужен простой и понятный полновесный графический интерфейс, а не просто запуск из командной строки. Пользователь задаёт кучу параметров, запускает различные тесты и может контролировать отдельные устройства и управлять или в ходе теста вручную. Кроме того, пользователь работает с механической частью, что тоже надо контролировать - во избежание. Всё это происходит без помощи программиста и рассчитано на людей, которые к программированию отношения не имеют. У меня интерфейс написан - из XML в wxWidgets генерит морды и подключается к межпроцессным очередям сообщений. Эта часть отработана. Я подозреваю, что скрипты привязать к межпроцессному обмену под вендой сложновато будет. К тому же, на Си я пишу с детства, со времён ДОСа и первого борландовского компилятора :), питоном я вообще никогда не интересовалась, а в перл я дальше регекспов не лазила.
Так что пока буду стремиться к совершенству на Си. А по ночам я один фиг не сплю, даже если программировать ничего срочно не надо - я не контрабасе играю на радость соседям :)
Tonal
Erlang таки не скрипт а виртуальная машина. Заточенная специально под телеком и довольно производительная (soft real-time). Процессы у ей свои, легковесные, поэтому их можно запустить гораздо больше и быстрее чем потоках в винде или линухе.
К тому же есть стандартный биндинг с wxWidgets, так что мордочку можно и старую сохранить. :)
Ежели тяжелых вычислений нет, то вполне может покатить.

С другой стороны, Erlang - это функциональный язык с иммутабельными переменными.
По отзывам, инженер не отягощённый знанием программинга вьезжает в него за неделю, другую.
Но если есть привычка к императивщине, то может оказаться изрядно сложно...

Да, про python: привязать его куда угодно вполне просто - очень вменяемый апи для расширений.
Ну и своих библиотек море. И IPC, и wxWidgets, и XML :)
Iron Bug
ну, тут много деталей... если даже виртуальная машина и быстрая (что, мягко говоря, сомнительно) - то как её связать с реальным железом, у которого может не быть стандартных драйверов и стандартных интерфейсов? боюсь, что тут гемора будет выше крыши. хотя вычислений у меня не так много и они простые, зато надо постоянно и шустро парсить поток байтов с драйвера и вылавливать из него нужные данные. так что тут задача довольно специфическая. вообще, к телекому это отношения не имеет: это обработка данных от специально разработанного железа и управление точной механикой на очень большой скорости. то есть, автоматизация промышленных процессов. сетевого взаимодействия на уровне тестирования просто нет. все данные льются по спецшинам и ДМА в корзину, где и обрабатываются. довольно специфическая задача, со своими требованиями.
что касается Эрланга... я бегло просмотрела в сети отзывы народа про него... судя по отзывам, Эрланг вроде как не используется для таких задач, как у нас. что он быстрее С# - ну дык... гы! меня шарп вообще не интересует ни с какой стороны, ибо дикие тормоза и чисто прикладная реализация, в принципе не рассчитанная на низкоуровневую работу с железом. для стандартных интерфейсов это может быть и проканает, но очень маловероятно, что в него можно внедрить работу с межпроцессным адресным пространством, различными системными объектами и фреймами ДМА в памяти. отзывы в плюс Эрлангу - в основном по объёму кода. но мне совершенно фиолетово на объём - мне не лень писать код, лишь бы он работал быстро и надёжно. конечно, оптимизация может быть во всём, но объём кода тут на самом последнем месте. к тому же всякие автоматические сборки мусора напрягают сразу: это означает фактическую непредсказуемость работы системы. я думаю, если в промышленной автоматизации и системном программировании никто за столько лет не написал ничего на таких языках - то это неспроста. так что я всё же придерживаюсь программирования на Си: простой и надёжный язык, на нём можно написать всё, что только захочется. а про Эрланг - ну, если появится время, можно будет глянуть спецификацию более детально. однако пока что мне кажется, что он не подходит для моих задач.
Andrew Selivanov
Цитата(Iron Bug @ 23.3.2009, 10:14) *
To Andrew Selivanov:
Руссинович у меня есть, но действительно довольно мутная книжка, сложно там что-то найти. Рихтер тоже ничего, гораздо более читабельно. Собственно, у меня вопросов-то почти не возникает, я под венду очень давно пишу. Про потоки в венде я и так знаю всё. Я и дрова для железа под неё писала, и сервисы, и всякие приблуды для юзеров, и всё, что только можно... Ну, архитектура у неё... эээ... КХМ... короче говоря, венда и есть венда! У компании пока по некоторым причинам нет планов переходить на линюкс, хотя давно пора уже! Мешает куча наработок и боязнь перехода. Собственно, планы всегда горят и особо времени нет, а кадров вечно не хватает... И вот сейчас у меня есть идея перейти на кроссплатформу и окончательно избавиться от мелкософтовских библиотек, что я уже успешно сделала в первом приближении. Но, как всегда бывает, сначала система была простой и логичной, но потом по требованиям юзеров обрастала всё новыми и новыми фичами, которые надо было городить срочно и которые всё хуже и хуже увязывались с изначально поставленными задачами... И вот программа превратилась в монстра, обвешанного костылями и стала ненадёжно работать. Поэтому я сейчас вот измышляю универсальную и стройную систему, чтобы учесть те требования, которые на данный момент существуют и, по возможности, предусмотреть возможность для безболезненной модификации при необходимости внесения новых фич. Более того, я замышляю линюксовый переворот хотя бы в области тестирования. Хочу попробовать написать пару дров и полностью протестировать работу машин под линём. Естессно, с демонстрацией преимуществ линюкса начальству! :) Я знаю, что я фанат, но тут ничего не поделать.

Про винду
Виндовая архитектура это вообще сплошные holy wars... Там поколения программистов оставили свои следы.

Про юзеров
Где то когда-то прочитал, что если просят ругаются и приносят баги - значит пользуются. Это хорошо :) Плохо, когда месяц трахался и "А.. спасибо" и - тишина...

Про костыли, горящие планы
Как знакомо :) Очевидно это у всех - следовательно - нормально.

Про кроссплатформу
Я для себя пришёл к выводу, что поддерживать КП без очень, очень веских на то причин - жутко затратная штука. Оттестил там - здесь отвалилось. Оттестил здесь - там отвалилось. Скачиваешь какой нибудь Open Source, вроде как КПный, а одна из версий - эммм... датирована годом эдак прошлым. Мягко говоря :)

Про C
Очевидно C++ :)

Про рефакторинг
Сам им страдаю периодически. Очень помогает изучение всякого качественного Open Source-a. Последнее время часто зависаю в коде DC++. Хорошая штука. А как там сделан протокол, автор мог бы статью отдельную написать. На радость разработчикам. Правда я не уверен, кто автор концепции.

Про Perl
Я его для себя воспринимаю как "Всё то, что бы хотели сделать в CMD, но не могли". СтОит потратить немного времени и понять про массивы, хэши, сокеты и прочее. IMHO.

Ударились во флейм и ушли от темы :) Думаю пора двинуть в специализированный раздел.
Влад
Iron Bug, вот я прочел и так и не понял: зачем все-таки плодить такое колоссальное количество потоков? Тем более, что 99.9% постоянно будут в состоянии ожидания, а когда же им дадут чуток поработать....
Мне кажется, здесь что-то не так в архитектуре приложения. Не лучше ли было бы использовать такие концепции, как "пул потоков" и "задание"? То есть, создается относительно небольшой пул рабочих потоков (размером, например, 2 * количество процессоров), и - баааальшая такая очередь заданий, которую они будут трудолюбиво разгребать. Как-то так.......
А при 2000 потоков они в основном будут бесполезно кушать ресурсы процесса, не успевая сделать ничего полезного.
Нет?
ViGOur
Цитата(Andrew Selivanov @ 23.3.2009, 18:52) *
Я для себя пришёл к выводу, что поддерживать КП без очень, очень веских на то причин - жутко затратная штука. Оттестил там - здесь отвалилось. Оттестил здесь - там отвалилось.
Не согласен. Если придерживаться стандартов и не привязываться к API, то все будет отлично. Если привязываться, то сложности в основном в планировании как и что будет работь.

Цитата(Влад @ 23.3.2009, 22:27) *
Мне кажется, здесь что-то не так в архитектуре приложения. Не лучше ли было бы использовать такие концепции, как "пул потоков" и "задание"? То есть, создается относительно небольшой пул рабочих потоков (размером, например, 2 * количество процессоров),
Как я понял у Iron Bug множество независимых железок, которые должны работать индивидуально и не запороть работу других.

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

Iron Bug поправь меня если я тебя не правильно понял.
Litkevich Yuriy
Цитата(ViGOur @ 24.3.2009, 2:52) *
Возьмем в качестве примера конвейер по сборке автомобиля, в нем множество независимых механизмов, которые выполняют свою работу, но должны быть синхронизированны между собой.
такую синхронизацию, на одном компьютере не делают, по моему опыту промавтоматики. И мне приходилось реализовывать подобные системы - компьютера в них небыло совсем.
Stranger
Цитата(Влад @ 23.3.2009, 22:27) *
Iron Bug, вот я прочел и так и не понял: зачем все-таки плодить такое колоссальное количество потоков? Тем более, что 99.9% постоянно будут в состоянии ожидания, а когда же им дадут чуток поработать....
Мне кажется, здесь что-то не так в архитектуре приложения. Не лучше ли было бы использовать такие концепции, как "пул потоков" и "задание"? То есть, создается относительно небольшой пул рабочих потоков (размером, например, 2 * количество процессоров), и - баааальшая такая очередь заданий, которую они будут трудолюбиво разгребать. Как-то так.......
А при 2000 потоков они в основном будут бесполезно кушать ресурсы процесса, не успевая сделать ничего полезного.
Нет?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.