На почве знакомства с Hoard'ом задумался над вопросом: а почему в популярных ОСях не используются thread-local менеджеры памяти? Или если используются, то какие?
Здравствуйте, Мишень-сан, Вы писали:
МС>На почве знакомства с Hoard'ом задумался над вопросом: а почему в популярных ОСях не используются thread-local менеджеры памяти? Или если используются, то какие?
Здравствуйте, Мишень-сан, Вы писали:
МС>На почве знакомства с Hoard'ом задумался над вопросом: а почему в популярных ОСях не используются thread-local менеджеры памяти? Или если используются, то какие?
см. TlsAlloc и etc
1. Обычно, в локальной памяти треда лежит только ссылка на общую область памяти. Таким образом ее можно передать в другой поток.
2. Время жизни неосновного потока обычно очень мало чтобы заморачиваться полноценным хранением.
3. В случае пула потоков — система летит нафиг.
Здравствуйте, Мишень-сан, Вы писали:
МС>На почве знакомства с Hoard'ом задумался над вопросом: а почему в популярных ОСях не используются thread-local менеджеры памяти? Или если используются, то какие?
Сравни быстродействие на нескольких потоках Hoard-а и простого HeapAlloc() в Windows 7 или Висте. Удивишься.
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, GlebZ, Вы писали:
GZ>>3. В случае пула потоков — система летит нафиг. CC>С чего бы вдруг?
Ну зависит от реализации пула — правильней говорить.
Здравствуйте, GlebZ, Вы писали:
GZ>>>3. В случае пула потоков — система летит нафиг. CC>>С чего бы вдруг? GZ>Ну зависит от реализации пула — правильней говорить.
Всё равно не особо понятно где ж там будет "система летит нафиг".
Возможна ситуация в которой per-thread allocator будет неэффективен, но корректно работать он будет всегда. Естественно речь про корректно написанный и полноценный аллокатор.
Здравствуйте, _Ursus_, Вы писали:
МС>>На почве знакомства с Hoard'ом задумался над вопросом: а почему в популярных ОСях не используются thread-local менеджеры памяти? Или если используются, то какие? _U_>Сравни быстродействие на нескольких потоках Hoard-а и простого HeapAlloc() в Windows 7 или Висте. Удивишься.
Hoard у меня под рукой нет, есть только самописный per-thread-pool allocator
LFH конечно неплохо себя показывает (он кстати доступен с ХР, если не раньше, просто его в Vista+ включают по умолчанию).
Но в многопоточке и при интенсивном выделении/освобождении памяти блокировки начинают сказываться.
Так что не убедил. Generic allocator он на то и generic что для всех случаев работает одинаково плохо.
Причина же, по которой не используются per-thread в качестве default allocator скорее в том, что такие аллокаторы идеально работают в реально тяжёлых многопоточных сценариях. Для generic использования они не оптимальны, а в случае "выделил в одном потоке, освободил в другом" могут стать сильно не оптимальны, как минимум в потреблении памяти (в случае deferred free реализации).
Здравствуйте, CreatorCray, Вы писали:
GZ>>Ну зависит от реализации пула — правильней говорить. CC>Всё равно не особо понятно где ж там будет "система летит нафиг". CC>Возможна ситуация в которой per-thread allocator будет неэффективен, но корректно работать он будет всегда. Естественно речь про корректно написанный и полноценный аллокатор.
Проблема скорее в пуле а не в аллокаторе. Стандартный пул Win32 ваще кладет на Tls. Поэтому если возврат пойдет по другому потоку (например при RegisteredWaitForSingleObject), удивлению не будет предела. Придется либо в воспитании себя и используемых библиотек — смотреть где можно а где нельзя пользоваться пулом, либо проксированием пула.
Что касается, например, Net ThreadPool, то там все средства представлены. Хотя тоже не без проблем.
Здравствуйте, GlebZ, Вы писали:
GZ>Проблема скорее в пуле а не в аллокаторе. Стандартный пул Win32 ваще кладет на Tls.
Начнём с того, что тут подразумевается под "стандартным пулом Win32".
GZ> Поэтому если возврат пойдет по другому потоку (например при RegisteredWaitForSingleObject), удивлению не будет предела.
Вот у меня тест создаёт потоки через CreateThread и передаёт между ними выделенные блоки. Освобождение блока в свежесозданном новом потоке не приводит ни к каким удивлениям. Совершенно штатная ситуация.
Здравствуйте, CreatorCray, Вы писали:
GZ>>Проблема скорее в пуле а не в аллокаторе. Стандартный пул Win32 ваще кладет на Tls. CC>Начнём с того, что тут подразумевается под "стандартным пулом Win32". http://search.microsoft.com/results.aspx?q=Thread+Pooling GZ>> Поэтому если возврат пойдет по другому потоку (например при RegisteredWaitForSingleObject), удивлению не будет предела. CC>Вот у меня тест создаёт потоки через CreateThread и передаёт между ними выделенные блоки. Освобождение блока в свежесозданном новом потоке не приводит ни к каким удивлениям. Совершенно штатная ситуация.
Мы ваще-то говорили о Thread Pool.
Здравствуйте, GlebZ, Вы писали:
GZ>Здравствуйте, CreatorCray, Вы писали:
GZ>>>Проблема скорее в пуле а не в аллокаторе. Стандартный пул Win32 ваще кладет на Tls. CC>>Начнём с того, что тут подразумевается под "стандартным пулом Win32". GZ>http://search.microsoft.com/results.aspx?q=Thread+Pooling
Ясно. Wrapper над обычными потоками.
Дык там с TLS всё в порядке. А именно при старте потока ничего с TLS не делается, как и ожидалось.
GZ>>> Поэтому если возврат пойдет по другому потоку (например при RegisteredWaitForSingleObject), удивлению не будет предела. CC>>Вот у меня тест создаёт потоки через CreateThread и передаёт между ними выделенные блоки. Освобождение блока в свежесозданном новом потоке не приводит ни к каким удивлениям. Совершенно штатная ситуация. GZ>Мы ваще-то говорили о Thread Pool.
В любом случае в пуле новый поток появляется через функции WinAPI. А именно CreateThread. Что TP_POOL что ручное управление — не суть важно в данном контексте.
Передача блока в другой поток для освобождения в правильно написанном аллокаторе не приводит к каким либо ошибкам. Память будет корректно освобождена, хотя скорее всего и не сразу.
Здравствуйте, Мишень-сан, Вы писали:
МС>На почве знакомства с Hoard'ом задумался над вопросом: а почему в популярных ОСях не используются thread-local менеджеры памяти? Или если используются, то какие?
Тоже задумывался о выгодах такого подхода, но на уровне пользовательских приложений (каждый сам кузнец своему счастью).
Можно иметь на каждый thread свой хип, возможно даже заведомо low-fragmented. Здесь, правда нюанс:
В HeapCreate можно задать флаг HEAP_NO_SERIALIZE, но с LFH он не уживается:
The low-fragmentation heap (LFH) cannot be enabled for a heap created with this option. (MSDN, HeapCreate function)
Однако, ничто не мешает отказаться от использования блокировки уже на этапе выделения/освобождения памяти: HeapAlloc, HeapRealloc и HeapFree поддерживают HEAP_NO_SERIALIZE.
Ну и assert'ом проверять, чтоб все операции выполнялись в пределах одного потока. И будет счастье.
Здравствуйте, d.4, Вы писали:
d.4>Однако, ничто не мешает отказаться от использования блокировки уже на этапе выделения/освобождения памяти: HeapAlloc, HeapRealloc и HeapFree поддерживают HEAP_NO_SERIALIZE.
Есть только одно "НО": в Vista+ в HEAP_NO_SERIALIZE прикрытая листьями кроется кучка свежайшего гуана.
Гуано же заключается в том, что при HEAP_NO_SERIALIZE в Vista+ используется какой то уникальнейший мегатормозной алгоритм, не имеющий аналогов и сливающий всем, даже Non-LFH режиму с сериализацией из WXP/2003.
Так что его юзать выходит в пару раз медленнее чем LFH с сериализацией на той же Vista+.
В до-vista виндах с HEAP_NO_SERIALIZE всё в порядке, работает как и ожидалось.
Ума не приложу на кой там насра накодили такое. Грызёт ощущение что это они из хулиганских побуждений нарочно.
Здравствуйте, CreatorCray, Вы писали:
CC>Ясно. Wrapper над обычными потоками. CC>Дык там с TLS всё в порядке. А именно при старте потока ничего с TLS не делается, как и ожидалось.
Нет. Это не wrapper. Его отличительная особенность в том, что он может поднять поток который уже использовался под другой задачей (вместе с его TLS). Точно также поток выполнения может отпустить текущий поток ожидая какое-то событие, и возобновить выполнение в другом потоке.
Здравствуйте, GlebZ, Вы писали:
GZ>Нет. Это не wrapper.
Я не совсем правильно выразился.
GZ>он может поднять поток который уже использовался под другой задачей (вместе с его TLS). Точно также поток выполнения может отпустить текущий поток ожидая какое-то событие, и возобновить выполнение в другом потоке.
Повторяю в ...наццатый раз: то, что в этом потоке уже создан пул для per-thread аллокатора никому не вредит. Он просто продолжает использоваться дальше уже новой задачей. При этом не будет никаких проблем освободить память, которая была выделена пока эта задача была в другом потоке.
Разумеется если аллокатор писан не криворукими идиотами.