Как отладить редкий тупик
Я пытаюсь отлаживать пользовательскую реализацию пула потоков, которая редко срабатывает. Поэтому я не могу использовать отладчик вроде gdb, потому что у меня есть клик, как 100-кратный отладчик "запуска", перед тем, как зайти в тупик.
В настоящее время я запускаю тест threadpool в бесконечном цикле в оболочке script, но это означает, что я не вижу переменных и т.д. Я пытаюсь использовать данные std::cout
, но это замедляет поток и уменьшает риск взаимоблокировок, что означает, что я могу подождать как 1 час с моим бесконечным до получения сообщений. Тогда я не получаю ошибку, и мне нужно больше сообщений, что означает ожидание еще одного часа...
Как эффективно отлаживать программу, чтобы ее перезапуск снова и снова до тех пор, пока она не будет заблокирована? (Или, может быть, я должен открыть другой вопрос со всем кодом для некоторой помощи?)
Заранее благодарю вас!
Бонусный вопрос: как проверить, все ли в порядке с std::condition_variable
? Вы не можете сказать, какой поток спал или если условие гонки происходит в состоянии wait
.
Ответы
Ответ 1
Существует два основных способа:
- Автоматизация работы программы в отладчике. Использование
gdb program -ex 'run <args>' -ex 'quit'
должно запускать программу под отладчиком, а затем выйти. Если программа все еще жива в той или иной форме (segfault или вы ее рубили вручную), вас попросят подтвердить.
- Прикрепите отладчик после воспроизведения тупика. Например, gdb может быть запущен как
gdb <program> <pid>
для присоединения к запущенной программе - просто подождите тупик и прикрепите его. Это особенно полезно, когда прикрепленный отладчик приводит к изменению времени, и вы больше не можете повторять ошибку.
Таким образом, вы можете просто запустить его в цикле и ждать результата, пока вы пьете кофе. BTW - мне легче найти второй вариант.
Ответ 2
Если это какая-то домашняя работа - перезапуск снова и снова с большим отлаживанием будет разумным подходом.
Если кто-то платит деньги за каждый час, который вы ждете, они могут предпочесть инвестировать в программное обеспечение, поддерживающее отладку на основе воспроизведения, то есть программное обеспечение, которое записывает все программа выполняет каждую инструкцию и позволяет повторять ее снова и снова, отлаживая назад и вперед. Таким образом, вместо добавления дополнительной отладки вы записываете сеанс, в течение которого происходит взаимоблокировка, и затем начинаете отладку непосредственно перед тем, как произойдет тупик. Вы можете шагнуть туда и обратно так часто, как хотите, пока не найдете виновника.
Программное обеспечение, упомянутое в ссылке, фактически поддерживает Linux и многопоточность.
Ответ 3
Вы можете запустить тестовый пример под GDB в цикле, используя команду, показанную в fooobar.com/questions/400595/...: gdb --eval-command=run --eval-command=quit --args ./a.out
.
Я сам использовал это: (while gdb --eval-command=run --eval-command=quit --args ./thread_testU ; do echo . ; done)
.
Как только он блокируется и не выходит, вы можете просто прервать его с помощью CTRL+C, чтобы войти в отладчик.
Ответ 4
Легкая быстрая отладка для поиска взаимоблокировок заключается в том, чтобы изменить некоторые глобальные переменные там, где вы хотите отлаживать, а затем распечатать их в обработчике сигналов. Вы можете использовать SIGINT (отправляется при прерывании с помощью ctrl+c
) или SIGTERM (отправляется, когда вы убиваете программу):
int dbg;
int multithreaded_function()
{
signal(SIGINT, dbg_sighandler);
...
dbg = someVar;
...
}
void dbg_sighandler(int)
{
std::cout << dbg1 << std::endl;
std::exit(EXIT_FAILURE);
}
Так же вы видите состояние всех ваших отладочных переменных при прерывании программы с помощью ctrl+c
.
Кроме того, вы можете запустить его в оболочке во время цикла:
$> while [ $? -eq 0 ]
do
./my_program
done
который будет запускать вашу программу навсегда до тех пор, пока не сработает ($?
- это статус выхода вашей программы, и вы выходите с EXIT_FAILURE в обработчике сигнала).
Это сработало для меня, особенно для того, чтобы узнать, сколько потоков прошло до и после каких блокировок.
Он довольно деревенский, но вам не нужен дополнительный инструмент, и он быстро реализуется.