Delphi DLL-потокобезопасность


У меня есть библиотека DLL Delphi, и я хочу загрузить ее в свое приложение внутри потока (более одного, чтобы быть точным). DLL просто создает объект, затем использует его и уничтожает. С этой точки зрения DLL-код является потокобезопасным.

Но что произойдет, если я загружу эту DLL в поток? Библиотека DLL все еще будет потокобезопасной? Что нужно знать о нити При загрузке DLL? Я видел, что VCL имеет свойство IsMultThread, которое устанавливается при создании потока, но получит ли dll уведомление об этом или я должен сделать это вручную?

3 6

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 под капотом.