остановить главный из потока - PullRequest
0 голосов
/ 04 февраля 2019

Я возился с C на моем Raspberry pi, мой main () раскручивает пару потоков, есть небольшой веб-сервер, который работает в одном из этих потоков,

int main(){
        printf("hello world\n");
        thisfn();
        pthread_t tid, led_tid;
        int port = 9193;
        int rc = pthread_create(&tid, NULL, webserver, &port);
        assert (rc == 0);
/snip

Если веб-серверне может привязаться к нужному порту, я хочу, чтобы вся программа остановилась.

void *webserver(void *vargp){
    int *port = (int *) vargp;
    printf("our port is %d\n", *port);

    /* First: Socket Creation */
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0){
            /* On error, -1 is returned */
            perror("Server Error!");
            abort();
    } else {
            printf("sockfd is %d\n", sockfd);
    }
    printf("Socket: sockfd: %d\n", sockfd);

    /* Second: Set socket options */
    int optval = 1;
    //int sockopt_int = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &optval, sizeof(optval) );
    int sockopt_int = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR , &optval, sizeof(optval) );
    if ( sockopt_int < 0 ){
            perror("Failed at setsockopt");
            abort();
    } else {
            printf("setsockopt succeeded\n");
    }

    /* Third: Bind to the port */
    /* int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); */
    struct sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(*port);

    int bind_int = bind(sockfd, (struct sockaddr *)&address, sizeof(address)) ;
    printf("bind_int ; %d\n", bind_int);
    if (bind_int < 0 ) {
            perror("Failed at bind");
            abort(); 
    } else {
            printf("bind succeeded\n");
    }

Я звонил abort (), я также пробовал выход (1), _exit (1) и т. Д., Однако при этом происходит утечка памяти (~ 136 байт) при проверке с помощью valgrind.

==13052== 136 bytes in 1 blocks are possibly lost in loss record 1 of 1
==13052==    at 0x4849CE0: calloc (vg_replace_malloc.c:711)
==13052==    by 0x401379B: allocate_dtv (dl-tls.c:322)
==13052==    by 0x40141D3: _dl_allocate_tls (dl-tls.c:539)
==13052==    by 0x489D9EF: allocate_stack (allocatestack.c:580)
==13052==    by 0x489D9EF: pthread_create@@GLIBC_2.4 (pthread_create.c:539)
==13052==    by 0x10EBF: main (fixmem.c:38)
==13052== 
==13052== LEAK SUMMARY:
==13052==    definitely lost: 0 bytes in 0 blocks
==13052==    indirectly lost: 0 bytes in 0 blocks
==13052==      possibly lost: 136 bytes in 1 blocks
==13052==    still reachable: 0 bytes in 0 blocks
==13052==         suppressed: 0 bytes in 0 blocks
==13052== 

Я узнал о школе мысли, что когда вещи попадают в вентилятор, все в порядке, чтобы выйти, позволяя ОС очищаться после.Я пытался заставить его выйти / прерваться с более счастливым Вэлгриндом.Я не делаю никаких явных mallocs / callocs в этой функции для вызова free () до abort () - и это приводит к моему вопросу:

Какой самый чистый способ остановить main и выйти из потока?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

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

Если вы хотите, чтобы вся программа остановилась, вполне нормально вызвать_exit() - вот для чего.

Не обращайте внимания на «утечки», о которых сообщает valgrind, они являются ложными срабатываниями, созданными тем фактом, что у кода очистки не было возможности запустить.Поскольку ОС освобождает всю память (и другие ресурсы), принадлежащие процессу, который вышел, на самом деле нет утечки памяти.

0 голосов
/ 04 февраля 2019

Подозреваю, что если веб-сервер успешно создан и поток завершается нормально, утечки памяти нет, верно?Если это так, основной поток может иметь некоторые ресурсы для очистки перед выходом (кажется, что pthread_create выделяет некоторую память).

Поэтому я могу предложить установить обработчик сигнала и выполнить корректное завершение вашего основного потока.Функция abort() отправляет сигнал на обработку.Таким образом, вы можете создать обработчик сигнала, чтобы перехватить такой сигнал в основном потоке и очистить его. Здесь хороший пример того, как это можно сделать.В примере SIGTERM перехватывается, и атомная переменная done устанавливается в 1. Эта переменная периодически проверяется в основном цикле, и в случае 1 программа завершается.Перед таким завершением вы можете остановить поток вашего веб-сервера и освободить память, выделенную в pthread_create.

(abort() отправляет SIGABRT, поэтому вам придется изменить код из примера)

Другие идеи:

  • Используйте pthread_join из основного потока для отслеживания кода выхода потока веб-сервера.В потоке веб-сервера вызовите pthread_exit, чтобы уведомить основной поток об ошибке и разрешить постепенное завершение.Учтите, что pthread_join заблокирует ваш основной поток.Но может быть хорошей идеей создать несколько рабочих потоков из основного и присоединиться к ним по очереди.

  • Используйте переменную Mutex / Conditional для уведомления основного потокаоб ошибке.Поток веб-сервера устанавливает такую ​​условную переменную в некоторый код ошибки и завершается с return.Основной поток будет следить за условной переменной и в случае ошибки завершать работу программы.

...