Delphi DLL-потокобезопасность
У меня есть библиотека DLL Delphi, и я хочу загрузить ее в свое приложение внутри потока (более одного, чтобы быть точным). DLL просто создает объект, затем использует его и уничтожает. С этой точки зрения DLL-код является потокобезопасным.
Но что произойдет, если я загружу эту DLL в поток? Библиотека DLL все еще будет потокобезопасной? Что нужно знать о нити При загрузке DLL? Я видел, что VCL имеет свойство IsMultThread, которое устанавливается при создании потока, но получит ли dll уведомление об этом или я должен сделать это вручную?
3 ответа:
Наиболее распространенной ловушкой является использование глобальных переменных. До тех пор, пока вы не используете глобальные переменные (или должным образом синхронизируете доступ к тем, которые вы используете), вы будете далеко идти к потокобезопасности.
IsMultiThread
используется, например, диспетчером памяти для оптимизации в однопоточном случае. Лично я не считаю, что это стоит оптимизировать в наши дни, так как практически весь полезный код имеет потоки некоторого описания. Я просто установилIsMultiThread
в True в начале вашей библиотеки DLL, например вbegin
/end
блок вашей библиотеки DLL .файл dpr, или в одном из разделов инициализации вашего устройства, что означает то же самое.Чтобы ответить на ваш вопрос напрямую, экземпляр
IsMultiThread
в вашей библиотеке DLL не будет установлен true, если вы не создадите поток в этой библиотеке DLL. Поскольку вы создаете потоки в своем EXE, вам нужно сделать это самостоятельно в DLL.В более общем плане, просто невозможно сказать много о потокобезопасности вашего кода, не зная, что он делает и что вы на самом деле подразумеваете под потокобезопасностью. Последний пункт может показаться странным, но я имею в виду вопрос, обсуждаемый в знаменитой книге Эрика Липперта что это за вещь, которую вы называете "потокобезопасной"? статья.
Установите
IsMultiThread
вTrue
первое в главном блоке вашего библиотечного проекта:library MyLibrary; begin IsMultiThread := True; ... end.
Это позволит диспетчеру памяти использовать потокобезопасные процедуры выделения / освобождения памяти.
Если вы будете осторожны в том, что вы делаете в потоке, вы будете в порядке. Если вам нужно обновить VCL основного потока, используйте synchronize, а еще лучше-не делайте этого.
У меня есть большая библиотека DLL, где я делаю много доступа к базе данных, и она работает в потоке. Все отлично работало в моих модульных тестах, но взлетало до небес, когда запускалось в потоке в главном приложении. Оказывается, мне пришлось перечитывать документы базы данных по потокобезопасности. В моем случае это DBISAM, и мне просто нужно было обязательно создать новую сессию для потоковый экземпляр базы данных, чтобы он не сталкивался с основным.
Еще одно место, где я столкнулся с проблемами (опять же, отлично работал в модульных тестах, потерпел неудачу в потоках), - это обработка XML. Мне пришлось вызвать CoInitialize / CoUnInitialize до / после использования XML DOM-файлов. Это справедливо для любого мыльного материала, который использует XML DOM под капотом.