С++, является set_terminate локальным для каждого потока?

Должен ли set_terminate/get_terminate установить другой обработчик исключений для нескольких потоков в С++ 2011 или С++ 2003?

например. если у меня есть программа и устанавливает обработчик завершения на func_1; затем я запускаю 3 потока. Что прекращают обработчики в новых потоках? Что, если в каждом потоке я установлю обработчик завершения на func_2 в первом потоке, func_3 во втором потоке и так далее.

N3242 (проект С++ 2011) ничего не говорит об этом в [handler.functions] или в [support.exception]/[exception.terminate]

PS: вы можете ответить на С++ 2011 или для С++ 2003 для любой популярной реализации этих стандартов

PPS: есть комментарий FCD для этого... С++ FCD Комментарий Статус Rev. 5 N3249 (2011):

GB 71    18.6.2.4 / 18.8.2.2 / 18.8.3.2   

Безопасность потока std::set_new_handler(), std::set_unexpected(), std::set_terminate() не указана, что делает невозможным использование функций поточно-безопасным способом.

Должны быть указаны гарантии безопасности потоков для функций, а также должны быть предусмотрены новые интерфейсы, которые позволят запросить и установить обработчики безопасным потоком.

LWG 1365 ПРИНЯТЬ С МОДИФИКАЦИЯми

См. документ N3189

Ответ 1

17.6.4.7p4 говорит:

Вызов функций set_* и get_* не должен приводить к гонке данных. Вызов любой из функций set_* должен синхронизироваться с последующими вызовами той же функции set_* и соответствующей функции get_*.

Это сильно означает, что функции set_* и get_* работают в одном и том же глобальном состоянии даже при вызове из разных потоков. Все абзацы под 18.8.3 обсуждают "текущую функцию обработчика", без каких-либо других упоминаний о потоке; это означает, что функция обработчика является свойством программы в целом; аналогично, 17.6.4.7 имеет:

2 - Программа С++ может устанавливать различные функции обработчика во время выполнения [...]
3 - Программа С++ может получить указатель на текущую функцию обработчика, вызвав следующие функции [...]

В этих параграфах обсуждается текущая функция обработчика в контексте программы, указывая, что это программная область, а не потоковая локальная.

Ответ 2

В стандарте говорится в

18.8.3.2 set_terminate [set.terminate]

terminate_handler set_terminate(terminate_handler f) noexcept;

1 Эффекты: Устанавливает функцию, обозначенную как f, как текущая функция обработчика для завершения обработки исключений.

[[noreturn]] void terminate() noexcept;

2 Эффекты: вызывает текущую функцию terminate_handler. [Примечание. По умолчанию terminate_handler всегда считается вызывающим обработчиком в этом контексте. -end note]

Вы можете видеть, что terminate() вызывает обработчик завершения current, который в разделе set_handler довольно четко говорит, что он используется для завершения процесса. Это вызвано, когда всякая обработка исключений прошла неудачно, независимо от того, какой поток работает.

Существует только один обработчик завершения, и он всегда вызывается из любой точки, где заканчивается программа.

Ответ 3

C2003 не имеет потоков, любая поддержка потоков - это расширение поставщика, поэтому в ответе есть только поставляемая поставщиком документация. Если обработчик соответствует потоку, документация должна сказать это. Никакая реализация, которую я знаю, не делает.

С++ 2011 ничего не говорит о характере обработчика terminate. Было бы мало смысла поддерживать его в потоке, потому что вы не можете убить нить в С++ 11. И по уважительной причине тоже (google kill + thread + С++ 11). Итак, что бы вы ни делали, программа должна завершиться. Похоже, что различные способы прекратить работу программы в зависимости от потока, который запросил, это не функция, которая вам нужна.

Ответ 4

В стандарте точно не указывается; [set.terminate] содержит только

[...] текущая функция обработчика для завершения обработки исключений.

но не упоминает, является ли "текущий" глобальным или потоковым. Так что это зависит от реализации.

Например, в MSVС++: https://msdn.microsoft.com/en-us/library/t6fk7h29.aspx

В многопоточной среде функции завершения сохраняются отдельно для каждого потока. Каждый новый поток должен установить свою собственную функцию завершения. Таким образом, каждый поток отвечает за собственную обработку завершения.