Какова напряженность между многопоточным и исключительной безопасностью на C++? Есть ли хорошие рекомендации? Прерывает ли поток из-за неперехваченного исключения?Написание многопоточного кода исключения-исключения
ответ
Я считаю, что стандарт C++ не упоминает многопоточность - многопоточность - это специфичная для платформы функция.
Я не совсем уверен, что в стандарте C++ говорится о неперехваченных исключениях в целом, но согласно this page, что происходит, определяется платформой, и вы должны узнать в документации своего компилятора.
В быстром и грязном тесте, который я сделал с g ++ 4.0.1 (i686-apple-darwin8-g ++ - 4.0.1), результатом является то, что вызывается terminate()
, который убивает всю программу. Код, который я использовал следующие:
#include <stdio.h>
#include <pthread.h>
void *threadproc(void *x)
{
throw 0;
return NULL;
}
int main(int argc, char **argv)
{
pthread_t t;
pthread_create(&t, NULL, threadproc, NULL);
void *ret;
pthread_join(t, &ret);
printf("ret = 0x%08x\n", ret);
return 0;
}
Собран с g++ threadtest.cc -lpthread -o threadtest
. Выход был:
terminate called after throwing an instance of 'int'
Я не рекомендую оставлять какие-либо исключения посторонними. Оберните функции потока верхнего уровня в обработчиках catch-all, которые могут более изящно (или, по крайней мере, verbosely) закрыть программу.
Хотя это * может * иметь смысл для некоторых приложений, я не согласен с ним в качестве общего совета. Обычно я рекомендую, чтобы люди обрабатывали исключения, когда это имеет смысл, иначе пусть они распространяются. Если вы правильно использовали RAII, вы не должны быть проблемой. – MattyT 2008-11-30 22:46:40
За исключением того, что ваши RAII-деструкторы не могут быть вызваны, если исключение не обнаружено. Реализация заключается в том, удаляет ли неиспользуемое исключение стек или нет. Он может просто прервать. Если вы поймаете все наверху, вы гарантируете стекирование. – 2008-11-30 22:58:55
Я думаю, самое главное помнить, что неперехваченные исключения из других потоков не отображаются пользователю или не бросаются в основной поток. Таким образом, вы должны деформировать весь код, который должен выполняться на потоках, отличных от основного потока, с блоками try/catch.
Неперехваченное исключение вызовет terminate()
, который в свою очередь вызывает terminate_handler
(который может быть установлен программой). По умолчанию terminate_handler
звонит abort()
.
Даже если вы переопределяете значение по умолчанию terminate_handler
, стандарт говорит, что подпрограмма, которую вы предоставляете, «прекращает выполнение программы, не возвращаясь к вызывающей» (ISO 14882-2003 18.6.1.3).
Итак, вкратце, неперехваченное исключение завершит программу не только потоком.
Что касается безопасности потоков, то как Adam Rosenfield говорит, что это специфичная для платформы вещь, которая не рассматривается стандартом.
Это единственная причина, по которой Эрланг существует.
Я не знаю, что такое конвенция, но imho, как можно больше, чем Эрланг. Делайте объекты кучи неизменяемыми и настраивайте какой-то протокол передачи сообщений для связи между потоками. Избегайте блокировок. Убедитесь, что передача сообщений безопасна для исключений. Храните в стеке столько штатных вещей.
Как уже обсуждалось, параллелизм (и, в частности, безопасность потоков) является архитектурной проблемой, которая влияет на то, как вы разрабатываете свою систему и свое приложение.
Но я хотел бы задать ваш вопрос о напряженности между безопасностью исключений и безопасностью потока.
На уровне класса для обеспечения безопасности потоков требуются изменения интерфейса. Так же, как безопасность исключений.Например, это обычное для классов, чтобы возвращать ссылки на внутренние переменные, скажем:
class Foo {
public:
void set_value(std::string const & s);
std::string const & value() const;
};
Если Foo используется несколькими потоками, беда ждет вас. Естественно, вы могли бы поставить мьютекс или другую блокировку для доступа к Foo. Но достаточно скоро все программисты на C++ захотят обернуть Foo в «ThreadSafeFoo». Мое утверждение, что интерфейс для Foo должен быть изменен на:
class Foo {
public:
void set_value(std::string const & s);
std::string value() const;
};
Да, это дороже, но это можно сделать поточно-замками внутри Foo. IMnsHO создает определенное напряжение между безопасностью потока и безопасностью исключений. Или, по крайней мере, вам нужно выполнить больше анализа, поскольку каждый класс, используемый как общий ресурс, должен быть рассмотрен под обоими огнями.
Есть два вопроса, которые я заметил:
в г ++ на Linux, убийство тредов (pthread_cancel) осуществляется путем выбрасывания «неизвестный» исключение. С одной стороны, это позволяет легко очищать, когда нить убивается. С другой стороны, если вы поймаете это исключение и не свернете его, ваш код заканчивается на abort(). Поэтому, если вы или любой из библиотек, которые вы используете убить темы, вы не можете иметь
улова (...)
без
throw;
в многопоточном коде. Here является ссылкой на это поведение в сети:
- Иногда вам необходимо передать исключение между потоками. Это непростая задача - мы закончили делать некоторые шаги, когда правильное решение - это способ сортировки/демаршаллинга, который вы используете между процессами.
C++ 0x будет иметь Language Support for Transporting Exceptions between Threads, так что, когда рабочий поток генерирует исключение, нерестовая нить может поймать или реконструировать его.
Из предложения:
namespace std {
typedef unspecified exception_ptr;
exception_ptr current_exception();
void rethrow_exception(exception_ptr p);
template< class E > exception_ptr copy_exception(E e);
}
Один классический пример (не могу вспомнить, где я видел его первый) в библиотеке станд.
Вот как вы поп-то из очереди:
T t;
t = q.front(); // may throw
q.pop();
Этот интерфейс несколько тупые по сравнению с:
T t = q.pop();
Но делается потому, что назначение T копия может бросить. Если копия вызывается после того, как поп произойдет, этот элемент будет потерян из очереди и никогда не сможет быть восстановлен. Но поскольку копия происходит до того, как элемент выскочил, вы можете поместить произвольную обработку вокруг копии из front() в блоки try/catch.
Недостатком является то, что вы не можете реализовать очередь, которая является потокобезопасной, с интерфейсом std :: queue из-за двух шагов. Что хорошо для безопасности исключений (разделение шагов, которые могут быть выбрасываться), теперь плохо для многопоточности.
Ваш главный спаситель в безопасности исключений - это то, что операции указателя не выбрасываются. Точно так же операции указателя могут быть сделаны атомами на большинстве платформ, поэтому они часто могут быть вашим спасителем в многопоточном коде. Вы можете получить свой торт и съесть его, но это действительно сложно.
- 1. Написание многопоточного приложения C#
- 2. Непонятный результат многопоточного кода
- 3. Обзор многопоточного кода C#
- 4. Большая сложность многопоточного кода
- 5. java.util.ConcurrentModificationException для многопоточного кода Java
- 6. Примеры хорошего многопоточного Java-кода?
- 7. Написание кода Поэма
- 8. Написание кода beautifier
- 9. Написание кода jQuery
- 10. Динамически написание Javascript-кода?
- 11. Написание тестового кода NUnit
- 12. Написание кода GRXML
- 13. Написание масштабируемого кода
- 14. Написание обобщенного кода
- 15. Написание гибкого кода
- 16. Написание кода бронирования (API)
- 17. Написание кода в цикле
- 18. Написание хорошего кода вопроса ....?
- 19. Написание многосерверного кода
- 20. Написание кода в MArkup
- 21. Написание четкого кода jQuery
- 22. Написание объектно-ориентированного многопоточного задания \ очередь результатов в python
- 23. SGE: Параллельная среда для многопоточного кода Java
- 24. Инструмент для просмотра многопоточного (C++/C) кода?
- 25. Библиотека для утверждения многопоточного кода на Java
- 26. Выход счетчика для этого многопоточного кода
- 27. Использование многопоточного кода и условия использования
- 28. Исключительное исключение указателя для многопоточного кода Java
- 29. Профилирование многопоточного кода, как работает выборка
- 30. Написание параллельного кода без блокировки кода
Я просто собирался написать то же самое. Просто сделайте более понятным, что приложение закончится (кто-то может понять, что только поток убит с завершением). terminate() приведет к тому, что все потоки будут убиты без дальнейшей обработки. – 2008-11-30 17:38:39
PS. Это поведение всех библиотек pthread, которые я использовал. – 2008-11-30 17:40:04