2017-01-09 2 views
2

я запускаю этот код в Visual Studio 2013 (Debug конфигурации):Visual Studio многопоточных отладки

#include <thread> 
#include <stdexcept> 

void c() { 
    /* breakpoint here*/ throw std::runtime_error("error"); 
} 

void b() { 
    c(); 
} 

void a() { 

    b(); 

} 

int main(int argc, char** argv) { 
    std::thread thr(a); 

    if (thr.joinable()) thr.join(); 

    return 0; 
} 

Выполнение останавливается в точке останова, и я вижу Call Stack:

> DemoProj.exe!c() Line 5 C++ 
DemoProj.exe!b() Line 10 C++ 
DemoProj.exe!a() Line 16 C++ 
[External Code] 

Это здорово ! Я точно вижу, где я нахожусь в процессе исполнения.

После этого я иду на один шаг (F10), чтобы выполнить эту линию исключения. Конечно, исключение брошено, но теперь мой Call Stack выглядит следующим образом:

> msvcp120d.dll!_Call_func$catch$0() Line 30 C++ 
msvcr120d.dll!_CallSettingFrame() Line 51 Unknown 
msvcr120d.dll!__CxxCallCatchBlock(_EXCEPTION_RECORD * pExcept) Line 1281 C++ 
ntdll.dll!RcConsolidateFrames() Unknown 
msvcp120d.dll!_Call_func(void * _Data) Line 28 C++ 
msvcr120d.dll!_callthreadstartex() Line 376 C 
msvcr120d.dll!_threadstartex(void * ptd) Line 359 C 
kernel32.dll!BaseThreadInitThunk() Unknown 
ntdll.dll!RtlUserThreadStart() Unknown 

Это делает мои отладки бесполезно. Линия

/* breakpoint here*/ throw std::runtime_error("error"); 

только здесь для этого простого примера. В реальном проекте я не буду знать, где код сломается. И было бы очень полезно, если Visual Studio могла остановить выполнение на точной строке, где произошла ошибка.

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

Любая помощь?

Я чувствую, что этот вопрос похож на this one. Идея заключается в том, чтобы перехватывать исключения в боковых нитях и передавать их в основной поток, чтобы основной поток мог повторно их выбросить. Разве нет еще более элегантного решения?

+2

После того, как исключение уже было поймано, вы ничего не можете сделать. Стек уже размотано. Однако вы можете написать свой собственный класс исключений, который выгружает стек (прочитайте StackWalk64), прежде чем что-то бросать. https://msdn.microsoft.com/en-us/library/windows/desktop/ms680650(v=vs.85).aspx –

+1

Отладчик обычно останавливается на необработанном исключении. Проблема в том, что она не обрабатывается. Вы видите код, который реализует требование о том, что вызов необработанных исключений заканчивается(). Это опасность std :: thread. Вам придется отлаживать этот вариант с помощью Debug> Exceptions> отметьте флажок Thrown для исключений C++. –

+1

Что вы хотите видеть в отладчике? Учитывая F10 шагов по линии, и все готово. Вы спрашиваете, как поймать exeception на другом аэде? – doctorlove

ответ

3

Было бы очень полезно, если Visual Studio могла остановить выполнение на точной строке, где произошла ошибка.

Visual Studio имеет возможность автоматически ломаться, когда генерируется исключение. В Vs 2015 это Debug -> Windows -> Настройки исключения. Установите флажок C++ Exceptions в разделе Break When Thrown.

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

+0

Да, это тот ответ, который я искал. MRB уже ответил на это в комментарии. Но я не могу принять комментарий в качестве ответа ... – ancajic

0

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

C++ 11 обеспечивает std::async, что это тип возвращаемого значения является std::future:

std::future<void> future = std::async(std::launch::async, []{ a(); }); 

Каждого Исключения брошено в другом потоке будет поймать и хранить в std::future объекте и выбросит, если вы звоните get на std::future.

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

+0

Я был не тем, кто был ниспослан, я надеюсь, что для этого downvote появится объяснение. – ancajic

+0

@ancajic Как я понимаю, вы хотите использовать способ регистрации исключений в параллельной среде, и я думаю, что это способ сделать это. – MRB

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