Должна ли пользовательская функция terminate() быть потокобезопасной?

Как указано в http://en.cppreference.com/w/cpp/error/terminate, есть много причин, чтобы вызвать terminate. Я могу представить себе случай, когда почти в одно и то же время некоторые из этих причин происходят в двух потоках.

Q1 Можно ли вызывать функцию завершения, установленную std::set_terminate дважды или более одновременно, к тому же, когда я имею в виду второй вызов, прежде чем он закончится.

  Thread1   Thread2
    |          |
    _          |
    t          |
    e          |
    r          |
    m          |
    i          _
    n          t
    a          e
    t          r
    e          m
    -          ?

Q2 Если Q1 == YES, то что произойдет, если первое завершение закончится. Я думаю, если это закончится с std:: abort, то программа закончится, но что произойдет, если пользователь предоставит завершение, не прерывает программу?

Q3 Является ли функция завершения, установленная std::set_terminate вызываемой в контексте потока, вызвавшей этот завершающий вызов?

Ответ 1

Q1

Да, std::terminate можно вызывать одновременно.

Q2

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

Q3

Функция, установленная std::terminate, является глобальной, а не локальной. Таким образом, один поток может воздействовать на другой.

В С++ 98/03 используется terminate_handler, когда terminate вызывается из-за неперехваченного исключения - это тот, который был действителен при вызове исключения, а не тот, который действует, когда terminate (хотя они, как правило, одинаковы).

В С++ 11 это было изменено, и теперь в стандарте говорится, что используемый обработчик является тем, который находится на месте в момент вызова terminate. Это изменение было сделано по ошибке и, скорее всего, будет исправлено в будущем проекте. Вот проблема LWG, отслеживающая эту проблему:

http://cplusplus.github.com/LWG/lwg-active.html#2111

Обновление

На совещании Spring 2015 г. в Lenexa, KS LWG решила стандартизировать существующее поведение и сделала его неуказанным, когда новый terminate_handler вступает в силу, если set_terminate вызывается во время разворачивания стека. То есть реализациям разрешено следовать либо правилам С++ 98/03, либо правилам С++ 11.

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