TOraDataSet блокирует мою программу, даже если для параметра NonBlocking установлено значение true

Я пытался сделать небольшой экран-заставку, чтобы моя программа могла открывать запросы без блокировки моего приложения. Код, который я написал, таков.

procedure TOpenThread.OpenTable;
begin
  FActiveTable.NonBlocking := true;
  FActiveTable.open;
end;
procedure TOpenThread.AbrirTablas;
begin
    FActiveTable := FOwnerPlan.TablasEdicion.Tabla;
    Synchronize(OpenTable);
    while FActiveTable.Executing do
    begin
     if Terminated then CancelExecution;
     sleep(10);
    end;
    FActiveTable.NonBlocking := false;
end;

Этот код выполняется в потоке и продолжает делать это, пока основной поток застревает.

Я использую delphi 2007


person Ismael Esteruelas Regalado    schedule 31.05.2017    source источник
comment
Где заблокирован основной поток?   -  person David Heffernan    schedule 31.05.2017


Ответы (1)


Этот код выполняется в потоке

Теперь это не так. Ваш код:

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
comment
Да, но свойство NonBlocking набора данных должно заставить его выполняться вне основного потока. - person Ismael Esteruelas Regalado; 31.05.2017
comment
Нет, метод OpenTable выполняется в основном потоке. Если нет - тогда нет причин беспокоиться о создании TOpenThread - просто вызовите .OpenTable из кода основного потока! Вопрос в том, что некоторые действия (но не все!) Больше не выполняются в OpenTable, а выгружаются для выполнения другими методами. Этого я точно не знаю. Однако что определенно верно, так это то, что Synchronize убивает многопоточность для своего параметра, это то, для чего был введен этот вызов. - person Arioch 'The; 31.05.2017