Комментарии по поводу DLL и безопасной многопоточной среды
Комментарии по поводу DLL и безопасной многопоточной среды
• Всякий раз, когда создается новый поток, вызывается функция DllMain с опцией DLL_THREAD_ATTACH, но для основного потока отдельного вызова с опцией DLL_THREAD_ATTACH не существует. В случае основного потока должна использоваться опция DLL_PROCESS_ATTACH.
• Вообще говоря, в том числе и в данном случае (возьмите, например, поток, принимающий сообщения (accept thread)), некоторым потокам распределение памяти может и не требоваться, но DllMain не в состоянии различать отдельные типы потоков. Поэтому на участке кода, соответствующем варианту выбора DLL_THREAD_ATTACH, фактического распределения памяти не происходит; здесь только инициализируется параметр TLS. Распределение памяти осуществляется точкой входа ReceiveCSMessage при первом ее вызове. Благодаря этому собственная память выделяется только тем потокам, которые в этом действительно нуждаются, и различные типы потоков получают ровно столько ресурсов, сколько им требуется.
• Хотя рассматриваемая библиотека DLL и обеспечивает безопасную многопоточную поддержку, любой поток в каждый момент времени может работать только с одним сокетом, поскольку долговременные состояния ассоциируются не с сокетами, а с потоками. Этот момент учитывается в следующем примере.
• Исходным кодом DLL, размещенным на Web-сайте, предусмотрен вывод общего количества вызовов DllMain в соответствии с их типами.
• Даже при таком решении существует риск утечки ресурсов. Некоторые потоки, например поток приема сообщений, могут вообще не завершаться, и поэтому не будут отсоединены от библиотеки DLL. Для остающихся активных потоков функция ExitProcess вызовет DllMain с опцией DLL_PROCESS_DETACH, а не DLL_THREAD_DETACH. В данном случае никаких проблем не возникает, поскольку поток приема сообщений никаких ресурсов не распределяет, а освобождение памяти происходит по завершении процесса. Однако, проблемы возможны в тех случаях, когда потоки распределяют такие ресурсы, как временные файлы. Поэтому окончательное решение должно предусматривать создание глобально доступного списка ресурсов. Тогда участок кода, соответствующий опции DLL_PROCESS_DETACH, мог бы взять на себя просмотр этого списка и освобождение ненужных ресурсов.