Вопрос или проблема
Я написал очень небольшую программу, которая создает два потока:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void *start()
{
printf("Я новый поток!\n");
printf("%d\n",pthread_self());
}
void main()
{
pthread_t thread_id1;
pthread_t thread_id2;
pthread_create(&thread_id1,NULL,start,NULL);
pthread_create(&thread_id2,NULL,start,NULL);
//pthread_join(thread_id,NULL);
sleep(30);
}
Когда я компилирую и запускаю программу с:
gcc create.c -lpthread
./a.out
И открываю новый терминал и пытаюсь просмотреть потоки, вот что я получаю:
ps -efL | grep a.out
root 1943 20158 1943 0 1 15:25 pts/4 00:00:00 ./a.out
root 1985 1889 1985 0 1 15:25 pts/5 00:00:00 grep --color=auto a.out
Так почему я не вижу здесь два идентификатора потоков?
Два дополнительных потока пишут свое сообщение и завершаются, поэтому у вас нет времени увидеть их с помощью ps
.
Новый поток завершается одним из следующих способов:
*
Он вызывает pthread_exit(3), указывая значение статуса выхода, доступное другому потоку в том же процессе, который вызывает
pthread_join(3).*
Он возвращается из start_routine(). Это эквивалентно вызову pthread_exit(3) с значением, указанным в операторе return.[…]
Вы можете отслеживать, что происходит, например, с помощью strace
:
$ strace -f -e trace=clone,exit ./a.out
clone(strace: процесс 409 подключен
child_stack=0x7f7126930ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f71269319d0, tls=0x7f7126931700, child_tidptr=0x7f71269319d0) = 409
[pid 408] clone(strace: процесс 410 подключен
child_stack=0x7f712612fff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f71261309d0, tls=0x7f7126130700, child_tidptr=0x7f71261309d0) = 410
Я новый поток!
Я новый поток!
647173888
638781184
[pid 409] exit(0 <незавершенный ...>
[pid 410] exit(0 <незавершенный ...>
[pid 409] <... выход возобновлен>) = ?
[pid 410] <... выход возобновлен>) = ?
[pid 410] +++ завершен с кодом 0 +++
[pid 409] +++ завершен с кодом 0 +++
Ответ или решение
Для того чтобы просмотреть потоки (threads) запущенного процесса, который создает дополнительные потоки, вам потребуются более специальные инструменты, чем просто команда ps
. Ниже подробно описано, как это сделать с использованием различных методов.
1. Изменение кода
Первое, с чего стоит начать — это сделать ваш код более управляемым. В настоящий момент потоки завершаются до того, как вы успеваете использовать ps
для их просмотра. Чтобы этого избежать, вы можете использовать pthread_join
, который заставит основной поток ждать завершения дочерних потоков:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void *start(void *arg) {
printf("Я новый поток! ID потока: %lu\n", pthread_self());
return NULL;
}
int main() {
pthread_t thread_id1;
pthread_t thread_id2;
pthread_create(&thread_id1, NULL, start, NULL);
pthread_create(&thread_id2, NULL, start, NULL);
// Ожидание завершения дочерних потоков
pthread_join(thread_id1, NULL);
pthread_join(thread_id2, NULL);
return 0;
}
2. Просмотр потоков с помощью ps
После добавления pthread_join
, вы можете запустить вашу программу и затем открыть новую терминальную сессию для выполнения команды:
ps -efL | grep a.out
Теперь вы должны увидеть два дополнительных потока, которые отвечают каждому из созданных вами потоков.
3. Использование инструмента top
Вы также можете использовать команду top
для просмотра всех потоков в процессе. Запустите top
и затем нажмите H
для переключения на режим просмотра потоков. В данном режиме вы сможете увидеть, как потоки вашего процесса создаются и завершаются в реальном времени.
4. Использование htop
htop
является более современным и удобным вариантом по сравнению с top
. Убедитесь, что он установлен, а затем запустите его:
htop
Нажмите F5
, чтобы переключиться на древовидный вид, что облегчает просмотр потоков, созданных вашим процессом.
5. Анализ с помощью strace
Если вам нужно отследить системные вызовы создания потоков, вы можете воспользоваться strace
:
strace -f -e trace=clone,exit ./a.out
Это позволит вам наблюдать за созданием потоков и их завершением, а также за другими вызовами. Вы сможете увидеть информацию о clone
и exit
, что поможет в диагностике состояния потоков.
6. Использование gdb
Если вам требуется мышление с дебаггингом, gdb
предоставляет мощные инструменты. Запустите вашу программу через gdb
:
gdb ./a.out
Затем используйте команды для вывода информации о потоках:
(gdb) run
(gdb) info threads
Заключение
Существует несколько способов мониторить создаваемые потоки в вашем приложении на C, каждый из которых имеет свои преимущества. Изменение вашего кода для корректного ожидания завершения потоков вместе с использованием инструментов командной строки, таких как ps
, top
, htop
, и strace
, предоставляют мощные возможности для отладки и мониторинга.