Можно ли вызывать pthread_exit из main? - PullRequest
13 голосов
/ 24 августа 2010

Когда я звоню pthread_exit из main, программа никогда не завершается. Я ожидал, что программа завершится, поскольку я выходил из единственного потока программы, но это не работает. Кажется, повесили.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int main(int argc, char *argv[])
{
    printf("-one-\n");

    pthread_exit(NULL);

    printf("-two-\n");
}

Process Explorer показывает, что (только) поток находится в состоянии Wait:DelayExecution.

Согласно pthread_exit документации:

Процесс должен завершиться с выходом статус 0 после последнего потока был прекращен. Поведение должно быть как будто реализация называется exit () с нулевым аргументом в потоке время окончания.

Я использую Dev-C ++ v4.9.9.2 и pthreads-win32 v2.8.0.0 (связывание с libpthreadGC2.a).

Библиотека вроде бы в порядке (например, вызов pthread_self или pthread_create из main работает нормально).

Есть ли какая-то причина, по которой я не должен звонить pthread_exit с main?

Ответы [ 4 ]

16 голосов
/ 24 августа 2010

Ну, это определенно допустимо в реализации pthreads в linux, см. Раздел примечаний в pthreads_exit . Это заявляет

Чтобы другие потоки могли продолжить выполнение, основной поток должен завершиться вызывая pthread_exit () вместо exit (3).

Далее, взгляд на исходный код здесь (torwads the end) показывает, что он примерно переводится в _endthread или _endthreadex. Документация здесь для тех, кто не упоминает о том, чтобы не вызывать ее в начальном потоке.

15 голосов
/ 24 августа 2010

Это совершенно законное и намеченное поведение.Весь процесс заканчивается только тогда, когда завершаются все потоки, или exit вызывается явно или неявно.

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

3 голосов
/ 25 сентября 2018

Хорошо использовать pthread_exit в main.Когда используется pthread_exit, основной поток прекращает выполнение и будет оставаться в состоянии зомби (перестал существовать) до тех пор, пока все другие потоки не завершатся.

Если вы используете pthread_exit в главном потоке, не можете получить статус возврата других потоков и не можете выполнить очистку для других потоков (это можно сделать с помощью pthread_join (3)).Кроме того, лучше отсоединять потоки (pthread_detach (3)), чтобы ресурсы потока автоматически высвобождались при завершении потока.Совместно используемые ресурсы не будут освобождены до тех пор, пока не завершатся все потоки.

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

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>

void *functionC(void *);

int main()
{
        int rc;
        pthread_t th;

        if(rc = pthread_create(&th, NULL, &functionC, NULL))
        {
                printf("Thread creation failed, return code %d, errno %d", rc,                 errno);
        }

        printf("Main thread %lu: Sleeping for 20 seconds\n", pthread_self());
        fflush(stdout);
        sleep(20);
        pthread_exit(NULL);
        printf("Main thread %lu: This will not be printed as we already called         pthread_exit\n", pthread_self());
        exit(0);
}

void *functionC(void *)
{
        printf("Thread %lu: Sleeping for 20 second\n", pthread_self());
        sleep(20);
        printf("Thread %lu: Came out of first and sleeping again\n", pthread_self());
        sleep(20);
        printf("CThread %lu: Came out of second sleep\n", pthread_self());
}

Вывод вышеуказанного кода:

Main thread 140166909204288: Sleeping for 20 seconds
Thread 140166900684544: Sleeping for 20 second
Thread 140166900684544: Came out of first and sleeping again
CThread 140166900684544: Came out of second sleep

ps вывод:

root@xxxx-VirtualBox:~/pthread_tst# ps -elfT |grep a.out
0 S root      9530  9530  9496  0  80   0 -  3722 hrtime 17:31 pts/1    00:00:00 ./a.out
1 S root      9530  9531  9496  0  80   0 -  3722 hrtime 17:31 pts/1    00:00:00 ./a.out
0 S root      9537  9537  2182  0  80   0 -  5384 pipe_w 17:31 pts/0    00:00:00 grep --color=auto a.out

root@xxxx-VirtualBox:~/pthread_tst# ps -elfT |grep a.out
0 Z root      9530  9530  9496  0  80   0 -     0 -      17:31 pts/1    00:00:00 [a.out] <defunct>
1 S root      9530  9531  9496  0  80   0 -  4258 hrtime 17:31 pts/1    00:00:00 ./a.out
0 S root      9539  9539  2182  0  80   0 -  5384 pipe_w 17:31 pts/0    00:00:00 grep     --color=auto a.out`

Пожалуйста, проверьте блог Tech Easy для получения дополнительной информации о потоках.

1 голос
/ 25 ноября 2016

При тестировании в Linux (CentOS Linux выпуск 7.2.1511 (Core)) я обнаружил, что главная программа действительно ожидает продолжения «дочерних» потоков.Также я не смог передать код возврата из main, хотя он может быть указан в качестве аргумента для pthread_exit (), как сказал выше Рауль, он всегда возвращает с кодом выхода 0:

retval=3;
pthread_exit(&retval);

Мы также наблюдалисообщение об ошибке при использовании компилятора Clang (версия 3.4.2) и параметров дезинфицирующего средства:

==5811==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x7f4c090321d0 in thread T0
#0 0x7f4c08be3e29 in __interceptor_free (/home/karstenburger/tests/libc/pthread_exit_in_main/a+0x65e29)
#1 0x7f4c08333358 in free_key_mem (/lib64/libdl.so.2+0x1358)
#2 0x7f4c08745bc1 in __nptl_deallocate_tsd (/lib64/libpthread.so.0+0x7bc1)
#3 0x7f4c07771b38 in __libc_start_main (/lib64/libc.so.6+0x21b38)
#4 0x7f4c08bfa08c in _start (/home/karstenburger/tests/libc/pthread_exit_in_main/a+0x7c08c)

AddressSanitizer can not describe address in more detail (wild memory access suspected).
SUMMARY: AddressSanitizer: bad-free ??:0 __interceptor_free
==5811==ABORTING
...