В Delphi является ли TDataSet потокобезопасным?
-
09-06-2019 - |
Вопрос
Я хотел бы иметь возможность асинхронно открывать TDataSet в его собственном потоке, чтобы основной поток VCL мог продолжаться до тех пор, пока это не будет сделано, а затем затем читать основной поток VCL из этого TDataSet.Я провел несколько экспериментов и попал в очень странные ситуации, поэтому мне интересно, делал ли кто-нибудь это раньше.
Я видел несколько примеров приложений, в которых TDataSet создается в отдельном потоке, открывается, а затем из него считываются данные, но все это делается в отдельном потоке.Мне интересно, безопасно ли читать TDataSet из основного потока VCL после того, как другой поток откроет источник данных.
Я занимаюсь программированием Win32 в Delphi 7, используя TmySQLQuery из ЦАП для MySQL как мой потомок TDataSet.
Решение
Если вы хотите использовать набор данных только в отдельном потоке, вы можете просто использовать синхронизацию для связи с основным потоком для любого обновления VCL/UI, как и с любым другим компонентом.
Или, что еще лучше, вы можете реализовать связь между основным и рабочим потоками с помощью собственной системы обмена сообщениями.
проверьте решение Холлварда для резьбы здесь:
http://hallvards.blogspot.com/2008/03/tdm6-knitting-your-own-threads.html
или вот этот:
http://dn.codegear.com/article/22411
для некоторого объяснения синхронизации и ее неэффективности:
http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/Ch3.html
Другие советы
Я видел это в других реализациях TDataSet, а именно в Аста компоненты.Они свяжутся с сервером, немедленно вернутся, а затем вызовут событие после загрузки данных.
Однако я считаю, что это во многом зависит от компонента.Например, те же самые компоненты Asta нельзя было открыть синхронно ни из чего, кроме основного потока VCL.
Короче говоря, я не считаю, что это ограничение TDataSet как таковое, а скорее что-то специфичное для реализации, и у меня нет доступа к упомянутым вами компонентам.
Одна вещь, которую следует иметь в виду при использовании одного и того же Тдатасет между несколькими потоками заключается в том, что в любой момент времени вы можете читать только текущую запись.Итак, если вы читаете запись в одном потоке, а затем вызывает другой поток Следующий тогда у тебя проблемы.
Также помните, что потоку, скорее всего, понадобится собственное соединение с базой данных.Я считаю, что здесь необходим многопоточный «хранящий» объект для загрузки данных из потока в (только запись), которые затем читаются только из основного потока VCL.Перед чтением используйте какой-либо метод синхронизации, чтобы гарантировать, что вы не читаете в тот же момент, когда пишете, или не пишете в тот же момент, когда читаете, или загрузите все в файл памяти и напишите метод синхронизации, чтобы сообщить основному приложению, где в файле нужно хватит читать.
Я использовал последний подход несколько раз, в зависимости от количества ожидаемых записей (и размера набора данных). Я даже перенес его в файл на физическом диске в локальной системе.Это работает довольно хорошо.
Я сделал многопоточный доступ к данным, и это не так просто:
1) Вам необходимо создать сеанс для каждого потока.
2) Все, что делается с этим экземпляром TDataSet, должно выполняться в контексте потока, в котором он был создан.Это непросто, если вы хотите разместить, например.сетка БД поверх него.
3) Если вы хотите, например.основной поток играет с вашими данными, простое решение – переместить их в какой-нибудь отдельный контейнер, например.Набор данных памяти.
4) Вам нужен какой-то механизм сигнализации для уведомления основного потока после завершения получения данных.
...и обработка исключений тоже непростая задача...
Но:Как только вам это удастся, приложение станет действительно элегантным!
Большинство TDatasets не являются потокобезопасными.Я знаю, что потокобезопасен: КБММемтабле.Он также имеет возможность клонировать набор данных, чтобы не возникала проблема перемещения указателя записи (как объяснил Джим МакКит).Это один из лучших наборов данных, которые вы можете получить (купить или бесплатно).