Что-то очень важное, что вам нужно понять о многопоточной разработке:
Каждый поток имеет свой собственный стек вызовов, почти , как если бы они были отдельнымипрограммы.Это включает основной поток вашей программы.
Потоки могут взаимодействовать друг с другом только особым образом:
- Они могут работать с общими данными или объектами. Это может привести к проблемам параллелизма, «гоночным условиям», и, следовательно, вы должны быть в состоянии помочь им «красиво делиться данными».Это подводит нас к следующему пункту.
- Они могут «сигнализировать друг другу», используя различные подпрограммы поддержки ОС.К ним относятся такие вещи, как:
- Мьютексы
- Критические секции
- События
- И, наконец, вы можете отправлять сообщения в другие темы. При условии, что поток каким-то образом записан как получатель сообщения.
NB : обратите внимание, что потоки не могут строго говоря вызывать другие темы напрямую.Например, если поток А попытался вызвать поток В напрямую, это было бы шагом в стеке вызовов потока А!
Это подводит нас к теме вопроса: "исключения не возникают вмои темы "
Причина этого заключается в том, что все исключение:
- Запишите ошибку
- И раскрутите вызов стека .<- NB: Ваш экземпляр TThread не может разматывать стек вызовов основного потока и не может произвольно прерывать выполнение основных потоков. </li>
Так что TThread не будет автоматически сообщить об исключениях в ваше основное приложение.
Вы должны принять явное решение относительно того, как вы хотите обрабатывать ошибки в потоках, и реализовать их соответствующим образом.
Решение
- Первый шаг такой же, как в однопоточном приложении.Вам необходимо решить, что означает ошибка и как должен реагировать поток.
- Должен ли поток продолжить обработку?
- Должен ли поток прерваться?
- Должна ли ошибка регистрироваться / сообщаться?
- Требуется ли решение пользователя?<- Это, безусловно, самый сложный для реализации, поэтому мы пока пропустим его. </li>
- Как только это будет решено, реализуйте соответствующий обработчик исключений.
TIP: Make sure the exception doesn't escape the thread. The OS won't like you if it does.
- Если вам нужна основная программа (поток), чтобы сообщить об ошибке пользователю, у вас есть несколько вариантов.
- Если поток был написан так, чтобы возвращать объект результата, то это легко: внести изменения, чтобы он мог возвращать ошибку в этом объекте, если что-то пошло не так.
- Отправить сообщениеОсновной поток, чтобы сообщить об ошибке.Обратите внимание, что основной поток уже реализует цикл сообщений, поэтому ваше приложение сообщит об ошибке, как только обработает это сообщение.
РЕДАКТИРОВАТЬ: Пример кода для указанноготребование.
Если все, что вы хотите сделать, это уведомить пользователя, то Ответ Cosmind Prund должен отлично работать для Delphi 2010. Старые версии Delphi требуют немного больше работы.Следующее концептуально похоже на собственный ответ Джеффа , но без ошибок:
procedure TUpdaterThread.ShowException;
begin
MessageDlg(FExceptionMessage, mtError, [mbOk], 0);
end;
procedure TUpdaterThread.Execute;
begin
try
raise Exception.Create('Test Exception');
//The code for your thread goes here
//
//
except
//Based on your requirement, the except block should be the outer-most block of your code
on E: Exception do
begin
FExceptionMessage := 'Exception: '+E.ClassName+'. '+E.Message;
Synchronize(ShowException);
end;
end;
end;
Некоторые важные исправления в ответе Джеффа, включая реализацию, показанную в его вопросе:
Вызов Terminate
имеет значение только в том случае, если ваш поток реализован в цикле while not Terminated do
....Посмотрите, что на самом деле делает метод Terminate
.
Вызов Exit
- ненужная трата, но вы, вероятно, сделали это из-за своей следующей ошибки.
В вашем вопросевы оборачиваете каждый шаг в свой try...except
для обработки исключения.Это абсолютное нет-нет !Делая это, вы притворяетесь, что, несмотря на исключение, все в порядке.Ваш поток пробует следующий шаг, но на самом деле гарантированно потерпит неудачу!Это не способ обработки исключений!