Не может поймать исключение в основном потоке, когда другой поток активен и имеет попытку поймать

Основной поток не может перехватить исключение (выброшенное в основном потоке), пока другой поток с try-catch все еще активен. Как это решить? пример:

int main()
{
  // try-catch of main thread
  try
  {
     // run a thread
     std::thread cThread([]()
     {
        // try-catch of secondary thread
        try
        {
           // makes thread works for 500 ms in order main thread will call
           // throw while thread is still active.  
           std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
        catch (...)
        {
        }
     });

     // Any call to throw BEFORE thread is finished, won't be catch.  
     // HOW TO SOLVE IT??
     throw 1;

     // wait thread finished
     cThread.join();

     // IF YOU PUT THE "throw 1" HERE (AFTER THREAD FINISHED), IT WILL BE 
     // CATCH.
   }
   catch (int e)
   {
      std::cout << "Catched exception " << e << " in main";
   }

   return 0;
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
566
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

Если вы объявите поток за пределами блока try-catch, исключение будет перехвачено. Помните, что вам также необходимо присоединиться к потоку, если возникло исключение.

хм.. теперь думаю об этом, возможно, thread.detach() перед броском тоже сработает.. но хм.. мне не нравится ни одно из решений..

quetzalcoatl 10.04.2019 13:49

Кстати. it should work - да, catch сработает, а ТОГДА завершит программу на return 0, когда std::thread пройдет внешнюю область видимости :):)

quetzalcoatl 10.04.2019 13:50

Спасибо, это было правильно. Я изменил его на std::async вместо std::thread.

audi02 10.04.2019 14:42

У тебя что-то не так. Я имею в виду, вы что-то неправильно поняли.

Это не может быть попытка поймать. 'throw' и 'try-catch' - внутрипоточные вещи, они живут только в текущем потоке, каким бы он ни был в момент броска, основным потоком или другим.

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

У вас есть вызов join() после броска, и вы ожидаете, что throw 1 пропустит его. Это правда. Однако в области видимости также есть переменная std::thread cThread.

Поскольку поток запущен и из-за throw 1 поток еще никогда не был присоединен(), то видимая вещь ожидал будет завершение программы (см. https://stackoverflow.com/a/13984169/717732), потому что деструктор std::thread обнаружит un-join( )ред нить. Это означает, что std::cout << "Catched exception " << e << " in main"; никогда не следует вызывать. Даже если поток каким-то образом завершился, ваша программа все равно должна завершиться, так как это не меняет того факта, что она не была объединена (см. https://en.cppreference.com/w/cpp/thread/thread/joinable)

Однако в зависимости от библиотеки, компилятора, отладчика и т. д. видимый эффект может отличаться. Например, если вы запустите его в отладчике, он может дождаться завершения всех потоков, и вы получите эффект «ожидания завершения внутреннего потока». Тяжело сказать.

Если вы действительно видите бегущую строку "Catched exception " << e << ", у вас настоящая проблема. Либо вы используете что-то другое, чем ваш текущий код, либо ваша stdlib не работает. Сломанная stdlib может, например, выполнять молчаливую функцию join() в деструкторе std::thread вместо завершения программы. Кто знает. Сломанная библиотека может делать многое.

Спасибо, это было правильно. Я изменил его на std::async вместо std::thread.

audi02 10.04.2019 14:43

Спасибо Молбднило и кетцалькоатль. Теперь я заставил код работать, используя std::async вместо std::thread:

Во-первых, проблема не связана с try-catch в потоке. Это была моя ошибка думать, что это так. Итак, вот код неисправности:

int main()
{
  // try-catch of main thread
  try
  {
     // run a thread
     std::thread cThread([]()
     {
     });

     // Any call to throw BEFORE thread join won't be catch.  
     // HOW TO SOLVE IT??
     throw 1;

     // wait thread finished
     cThread.join();

     // IF YOU PUT THE "throw 1" HERE (AFTER THREAD FINISHED), IT WILL BE 
     // CATCH.
   }
   catch (int e)
   {
      std::cout << "Catched exception " << e << " in main";
   }

   return 0;
}

И код, который работает:

int main()
{
  std::future<void> cF;

  // try-catch of main thread
  try
  {
     // run a thread
     cF = std::async(std::launch::async, []()
     {
     });

     // You can call throw , it will be catch :)  
     throw 1;

     // wait thread finished
     if (cF.valid())
     {
        cF.get();
     }
   }
   catch (int e)
   {
      std::cout << "Catched exception " << e << " in main";
   }

   return 0;
}

Другие вопросы по теме