2016-12-29 5 views
0

У меня возникли проблемы с обработкой исключений в многопоточном коде C++. Следующая программа выходит с terminate called without an active exception Aborted (core dumped).std :: обработка потоков и исключений

#include <thread> 
#include <iostream> 
#include <stdexcept> 

struct Thing { 

    void runComponent() 
    { 
     throw std::runtime_error("oh no!\n"); 
    } 

    void runController() 
    { 
     while (true) {} 
    } 

    void run() 
    { 
     auto control_thread = std::thread([this] { runController(); }); 

     runComponent(); 

     if (control_thread.joinable()) 
      control_thread.join(); 
    } 
}; 

int main() 
{ 
    try { 
     Thing thing; 
     thing.run(); 
    } catch (std::runtime_error &ex) { 
     std::cerr << ex.what(); 
    } 
} 

Вместо этого, я хотел бы, чтобы обработать исключение в блоке try catch в main(). Я понимаю, что исключения не передаются (обычно) между потоками, так как потоки имеют собственный стек. Проблема здесь (мне кажется) заключается в том, что исключение не обрабатывается, даже если оно генерируется в не-forked-потоке. Если я прокомментирую строки в run(), имеющие отношение к control_thread, все будет хорошо.

Составлено с clang-3.8 и -std=c++11 main.cpp -lpthread.

+0

@ Может быть. Я знаю «exception_ptr». Но проблема здесь (я думаю ..) заключается в том, что метатель (runComponent) фактически находится в основном потоке. Нужно ли использовать указатель исключения даже в этом случае? – jonnew

+0

Ответил в ответе ниже! Я неправильно понял вопрос – Curious

ответ

1

Проблема заключается в том, что вы не звоните detach() или join() на тему, которую вы создаете в методе run(). Это ошибка в потоках C++. См When should I use std::thread::detach?

Если вы измените свой код на любой из приведенных ниже, то все работает отлично

#include <thread> 
#include <iostream> 
#include <stdexcept> 

struct Thing { 

    void runComponent() 
    { 
     throw std::runtime_error("oh no!\n"); 
    } 

    void runController() 
    { 
     return; 
    } 

    void run() 
    { 
     auto control_thread = std::thread([this] { runController(); }); 
     // either of the following two will work 
     // control_thread.join(); 
     control_thread.detach(); 

     runComponent(); 
    } 
}; 

int main() 
{ 
    try { 
     Thing thing; 
     thing.run(); 
    } catch (std::runtime_error &ex) { 
     std::cerr << ex.what(); 
    } 
} 

Похоже, что вы хотели было отсоединение, вот почему я отсоединил нить в приведенном выше примере. Если это не то, что вы хотите, вам, вероятно, понадобится другой способ обработать поток потока join(). Если вы хотите, чтобы основной поток и другой поток функционировали независимо, вам понадобится другая синхронизация.

+0

Да, это работает. Я думаю, что мне нужно отсоединиться, но я отмечаю, что точка поднята в ответе на ссылку SO, которую вы предоставляете. Если вам не нужно иметь больше гибкости, и я хочу предоставить механизм синхронизации, чтобы дождаться завершения потока самостоятельно, в котором если вы можете использовать отсоединение ». В этом конкретном случае, что это значит? Будут ли освобождены ресурсы, выделенные 'runController()', если я использую detach? – jonnew

+0

Кроме того, «ошибка в потоках C++» вы имеете в виду в стандартной реализации библиотеки? – jonnew

+0

@jonnew Я думаю, что это означает, что если вам нужен какой-то пользовательский способ обработки исключений, тогда вам придется реализовать его вручную с помощью блокировок. Самое простое - составить список потоков, в которых есть потоки для потоков в порядке, в котором произошли исключения. Я не думаю, что это соответствует – Curious

Смежные вопросы