основной поток "заблокирован на критическом участке, который заброшен" - PullRequest
1 голос
/ 07 января 2011

У меня есть многопоточное приложение, использующее OmniThreadLibrary . Я неправильно использую OTL для открытия хранимых процедур ADO во вторичных потоках, который работает, если нет ошибки (и в основном даже тогда). К сожалению, в данном конкретном случае есть проблема.

Когда я открываю определенную форму, я получаю исключение в потоке «Должно быть хотя бы одно поле», копирующего набор данных в таблицу памяти kb, которую я обрабатываю и отправляю сообщение в поток мониторинга. Это сообщение приходит и успешно сохраняется в базе данных. Когда я закрываю эту форму, основной поток VCL зависает.

kbMemTable.LoadFromDataset(StoredProc, []); // throws

Приостановка приложения в отладчике и просмотр списка потоков, который показывает основной поток VCL:

"Blocked on critical section which is abandoned owned by Process 0"

Потоки OTL все еще находятся в рабочем состоянии и время истекло из пула потоков, поэтому кажется, что все работает, кроме основного потока. Я также использую компоненты DevExpress и Raise, которые имеют свои собственные потоки, но не называют их (и, похоже, не являются частью проблемы), что означает, что у меня 12 потоков, из которых только 5 идентифицируемы.

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

Это включает слишком много исходного кода для включения, и мое тестовое приложение не отображает поведение.

Я прошу любые советы по отслеживанию этого.

Моя текущая мысль - переключаться на отладку dcu и точки останова при каждом критическом создании раздела, которое я могу найти, а затем посмотреть, что произойдет. Я мог бы решить проблему, которая вызывает первое исключение, но я обеспокоен тем, что какое-то другое исключение может иметь такой же эффект в той области, где было бы больно иметь дело. Поэтому я хотел бы сначала решить эту проблему.

Редактировать: критический раздел принадлежит потоку, который вызывает TADOStroredProc.ExecProc. Этот поток обычно завершает работу после обработки исключения, поэтому, если я не прыгну в отладчик быстро, поток выйдет из пула, прежде чем я его увижу, следовательно, ProcessID = 0 выше. Установка времени ожидания потока на 60 секунд вместо 10 секунд, по крайней мере, дает мне это.

Ответы [ 2 ]

2 голосов
/ 07 января 2011

Во-первых, я не понимаю, почему вы называете открытие хранимого процесса ADO в фоновом потоке "неправильным использованием" - оно должно работать без сбоев, , если у вас нет путаницы в разных потоках ' квартиры или другие сообщения (например, уведомления о потоке мониторинга).

Я не знаю, что именно является причиной вашей проблемы, но я поделюсь некоторым опытом в области многопоточности Delphi ADO. Обмен сообщениями COM / OLE STA является основным подозреваемым здесь.

Фоновые темы действительно должны быть как MTA. Я не знаю, делает ли Delphi 2010 это сам по себе, но Delphi 2006 этого не делает - чтобы убедиться, что в источниках есть вызовы CoInitializeEx - если не вызывается с флагом COINIT_MULTITHREADED=$00, поток считается квартира нейтральна и маршалы через STA / основной поток. Любой другой метод инициализации даст вам хороший поток STA.

Вы должны:

  • предоставит вашим фоновым потокам правильную инициализацию / завершение COM как MTA
  • использовать все компоненты ADO только из квартиры, в которой они были созданы
  • не создавать другие потоки STA (основной поток по умолчанию один); объединение сообщений с другими блокировками - это слишком много PITA
  • никогда не использовать асинхронные возможности ADO вместе с многопоточностью
1 голос
/ 07 января 2011

Я предлагаю вам использовать библиотеку журналов, такую ​​как CodeSite, чтобы отследить, где остановлен основной поток.

...