Этот код выполняется в потоке
Теперь это не так. Ваш код:
Synchronize(OpenTable);
Это явно означает, что OpenTable
процедура выполняется в основном потоке VCL и вне фонового вспомогательного TOpenThread
.
Дополнительные сведения о Synchronize
, у которых вы можете попытаться узнать, см. https://stackoverflow.com/a/44162039/976391.
В общем, простых решений сложных проблем просто не бывает.
Если вы хотите выгрузить взаимодействия с БД в отдельный поток, вам придется сделать этот поток эксклюзивным владельцем и пользователем всех компонентов БД, начиная с самого соединения с БД и до каждой транзакции и каждого запроса.
Затем вам нужно будет найти средства для АСИНХРОННОЙ отправки запросов данных из основного потока VCL во вспомогательный поток БД и АСИНХРОННО получать от него пакеты данных. Что-то вроде OmniThreadLibrary работает с потоками данных - прочтите их руководства, чтобы понять суть внутренней структуры программы при использовании многопоточности.
Вы можете ПОПРОБОВАТЬ изменить свое приложение в соответствии со следующими практическими правилами. Это будет не самая быстрая многопоточность, но, возможно, самая простая.
все компоненты базы данных работают исключительно внутри TOpenThread.Execute
контекста, и эти компоненты являются локальными переменными-членами класса TOpenThread
. Подключение-отключение производится только в пределах TOpenThread.Execute
; TOpenThread.Execute
ожидает команд от основного потока в почти бесконечном (пока поток не будет завершен) и регулируемом цикле.
конкретные запросы к базе данных выполняются как anonymous procedures
и добавляются к некоторому TThreadedQueue<T>
общедоступному члену объекта TOpenThread
. Цикл внутри .Execute
пытается получить действие из этой очереди и выполнить его, если оно существует, или дросселировать (Yield()
), если очередь пуста. Ни Synchronize
, ни Queue
оболочки не допускаются для операций с базой данных. Основной поток VCL только отправляет запросы, но НИКОГДА не ждет их фактического выполнения.
эти анонимные процедуры после выполнения передают результаты базы данных обратно в основной поток. Например, http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/ или как Отправка данных из TThread на главную VCL Thread или любым другим способом возврата в основной поток.
TOpenThread.Execute
выходит из цикла, только если установлен флаг Terminated
и очередь пуста. Если установлено Terminated
, при немедленном выходе будут потеряны действия, все еще ожидающие в очереди, не обработанной.
Кажется скучным и утомительным, но простым? Вовсе нет, добавьте туда, что вам придется перехватывать исключения и обрабатывать все ошибки асинхронным способом - и вы «потеряете всякую надежду, войдя в эту область».
PS. и последнее, но не менее важное, о предположении «Этот код выполняется в потоке и продолжает делать это, пока основной поток застревает», честно говоря, я предполагаю, что вы ошибаетесь здесь, и я думаю, что ОБЕИ ваши потоки застревают друг у друга . Не понимая полностью, как межпоточная блокировка предназначена для работы в этом конкретном компоненте, коде ковровой бомбардировки с вызовами Synchronize
и других инструментов межпоточной блокировки, у вас есть шанс просто загнать их все ваши потоки в состояние взаимной блокировки, тупика. См. http://stackoverflow.com/questions/34512/.
person
Arioch 'The
schedule
31.05.2017