Россия |
Атрибуты нитей и управление нитями
Отладка многопоточных программ в gdb
Gdb назначает всем нитям отлаживаемой программы собственные числовые идентификаторы, обычно совпадающие с порядком создания этих нитей, но не обязательно с системными идентификаторами соответствующих нитей и LWP. Эти идентификаторы выводятся во второй колонке вывода команды info threads. Все остальные команды, оперирующие нитями, используют эти идентификаторы для ссылки на конкретные нити.
Одна из нитей программы является текущей с точки зрения gdb. Эта нить отмечается символом * в выводе команды info threads. Переключить текущую нить можно командой thread threadno, где threadno – идентификатор нити в терминах gdb. Кроме того, если нить, отличная от текущей, достигла точки останова ( breakpoint ), отладчик автоматически переключается на нее.
Команды пошагового исполнения( step, next, finish и др.) исполняются в контексте текущей нити. Также, команды выдачи значений локальных переменных и стека оперируют стеком текущей нити.
При остановках программы по любой причине (точка останова, пошаговое исполнение и др.) отладчик останавливает исполнение всех нитей программы. При продолжении исполнения продолжается исполнение всех активных нитей программы. Однако способа синхронизовать это исполнение, например пошагово исполняя по одной строке исходного кода в нескольких нитях, не существует. На практике, при пошаговом исполнении одной из нитей остальные нити будут останавливаться не на границах операторов исходного кода, а на произвольных командах.
Точки останова ( breakpoint ) по умолчанию создаются для всего процесса, т.е. приводят к остановке любой нити, достигшей этой точки. Однако можно создавать точки останова для отдельных нитей. Точный синтаксис команды установки точки останова таков: break linespec [thread threadno] [if condition]. Квадратными скобками отмечены необязательные параметры команды.
linespec определяет номер строки исходного кода или адрес команды, на которой будет установлена точка. Gdb поддерживает несколько способов задания номера строки (номер строки в файле, номер строки в функции, номер строки относительно текущей). threadno представляет собой идентификатор нити, назначенный gdb. condition представляет собой условие, заданное при помощи подмножества языка программирования, при котором будет срабатывать точка останова. Точки останова без условий срабатывают при любой передаче управления на точку останова.
При отладке программ на языках C/C++ в качестве языка, на котором задаются условия, используется подмножество C. В действительности, условия можно задавать на любом из языков, поддерживаемых gdb; gdb определяет язык, на котором написан модуль программы, по расширению файла исходного текста. Кроме того, язык можно менять явно командой set language. Команда set language без параметров выводит список всех языков, поддерживаемых вашей версией gdb.
Полная документация по gdb может быть найдена на домашней странице проекта GDB по адресу http://sourceware.org/gdb/documentation/.
Отладка многопоточных программ в dbx
Dbx – это отладчик, входящий в состав SunStudio. Он может использоваться как самостоятельный отладчик с командным интерфейсом либо как часть графического экранного отладчика SunStudio. Полная документация по командному режиму dbx доступна по адресу http://docs.sun.com/app/docs/doc/819-3683.
Dbx в командном режиме имеет возможность эмулировать gdb ; для этого следует исполнить команду gdb on. После этого отладчик начнет воспринимать значительное подмножество команд gdb, но перестанет понимать команды dbx. Вернуться в основной режим можно командой gdb off.
В "родном" режиме dbx список нитей текущего процесса выводится командой threads (см. пример 4.3)
(dbx) threads t@1 a l@1 ?() running in main() t@2 ?() asleep on 0xef751450 in_swtch() t@3 b l@2 ?() running in sigwait() t@4 consumer() asleep on 0x22bb0 in _lwp_sema_wait() *>t@5 b l@4 consumer() breakpoint in Queue_dequeue() t@6 b l@5 producer() running in _thread_start() (dbx)4.3. выдача команды threads
Символы * или o отмечают нить, в которой произошло событие, требующее внимания отладчика. В примере 4.3 это точка останова. Символ > отмечает текущую (с точки зрения отладчика) нить. В отличие от gdb, эти нити могут не совпадать. t@number обозначает идентификатор нити в терминах dbx. l@number обозначает LWP, к которому привязана или в рамках которого исполняется нить.
Внимательный читатель может догадаться, что в примере 3 приводится результат отладки программы, использующей старую реализацию POSIX Threads API, в которой нитей могло быть больше, чем LWP.
За l@number выводится стартовая функция нити (функция, которая была передана в качестве параметра pthread_create(3C) ), текущее состояние нити и имя функции, которую нить исполняет в данный момент.
Список LWP процесса может быть выведен командой lwps (см. пример 4.4).
dbx) lwps l@1 running in main() l@2 running in sigwait() l@3 running in _lwp_sema_wait() *>l@4 breakpoint in Queue_dequeue() l@5 running in _thread_start() (dbx)4.4. Вывод команды lwps
Как и gdb, dbx является синхронным отладчиком. Это означает, что при остановке любой из нитей процесса по любой причине останавливаются все нити этого процесса. Поэтому состояние нити running означает, что эта нить готова к исполнению, но остановлена отладчиком.
Переключение текущей нити осуществляется командой thread threadid. Команда thread без параметров выводит номер текущей нити. При помощи команды thread можно осуществлять ряд других операций над нитями. Полный список опций команды thread приводится в документации или во встроенной справке dbx, которую можно вызвать командой help thread.
Команды пошагового исполнения и анализа содержимого стека выполняются по отношению к текущей нити. При пошаговом исполнении на время каждого шага возобновляется исполнение всех готовых к исполнению нитей.
Отладка многопоточных программ в SunStudio
Интегрированная среда разработки SunStudio 11 основана на NetBeans и содержит многооконный экранный отладчик. В действительности этот отладчик представляет собой графический интерфейс к отладчику dbx. В одном из окон доступна командная строка dbx и можно исполнять произвольные команды dbx.
На рис 4.1 приводится снимок экрана SunStudio при отладке многопоточной программы.
В верхнем окне левой панели (окно так и озаглавлено – Threads) виден список всех нитей процесса с указанием их состояний и текущей исполняемой функции. Формат, в котором выводится описание каждой из нитей, аналогичен формату вывода команды threads отладчика dbx. Текущая нить выделена.
На рис. 4.2 приводится вид той же отладочной сессии после переключения текущей нити.
Характерная бледно-розовая отметка строки printf("Child\n") ; обозначает, что исполнение нити остановлено в этой строке, но не точно на границе строки. Стек вызовов, выведенный в окне "Call Stack" позволяет увидеть, где именно остановлено исполнение.