проблема завершения потока (c программирование) - PullRequest
2 голосов
/ 13 ноября 2009

Я работаю над приложением для Linux на C, которое использует несколько потоков. Потоки, порожденные основной функцией, выполняют большую часть работы и поэтому обычно заканчиваются последними. Я наблюдаю какое-то странное поведение, и я полагаю, что это связано с тем, что основной поток прерывается до того, как порожденные потоки имеют возможность завершить свою работу. Вот пример кода для иллюстрации того, о чем я говорю:

#define _POSIX_C_SOURCE 200112L
#define _ISOC99_SOURCE
#define __EXTENSIONS__
#define _GNU_SOURCE

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

void
my_cleanup(void *arg)
{
     printf("cleanup: %s\n", (char *)arg);
}


void *
thread_stuff(void *arg)
{
     printf("thread started\n");
     pthread_cleanup_push(cleanup, "running");
     if (arg)
          pthread_exit((void *)2);
     pthread_cleanup_pop(0);
     pthread_exit((void *)2);
}


int
main()
{
     int err;
     pthread_t tid1, tid2;

     err = pthread_create(&tid1, NULL, thread_stuff, (void *)1);
     err = pthread_create(&tid2, NULL, thread_stuff, (void *)1);

     sleep(10);                 /* change the value here if you want */

     return SUCCESS;
}

Когда этот код запускается, сообщение из функции очистки печатается дважды, как и должно быть, но в других случаях при его запуске я вижу сообщение, напечатанное только один раз, а иногда я вижу его напечатанным три раза или нет вообще. Вы добавляете функцию сна в основную функцию, чтобы играть с тем, сколько времени требуется для завершения основной функции.

Что я могу сделать, чтобы программа работала должным образом? Я подозреваю, что это как-то связано с присоединением к детям, но я не совсем понимаю концепцию объединения или как применить его в этой ситуации.

Заранее спасибо!

Ответы [ 3 ]

3 голосов
/ 13 ноября 2009

Да, вы должны "присоединиться" к темам. «Присоединение» к потоку просто означает ожидание завершения потока. Другими словами, вы бы сделали

pthread_join(tid1, NULL);
pthread_join(tid2, NULL);

чтобы дождаться завершения обоих потоков.

Редактировать: Что делать, если у вас есть дочерний поток, который, в свою очередь, создает поток "внука"? Как правило, тот, кто создал поток, должен дождаться его завершения («присоединиться» к нему). Таким образом, в этом сценарии дочерний поток вызовет phtread_join в потоке внука, а основной поток вызовет соединение в дочернем потоке.

2 голосов
/ 13 ноября 2009

Я думаю, что вы хотите запускать pthread_join в каждом из потоков, когда ваш основной поток завершает работу - это останавливает основной поток, пока данный поток не завершит свою работу. Однако другие потоки все еще могут завершиться первыми, поэтому выполнение pthread_join в каждом потоке предотвратит завершение основного потока до тех пор, пока не завершатся все остальные.

1 голос
/ 10 июля 2012

Существует определенная проблема, если main () завершает работу перед потоками, которые он породил, если вы не вызываете pthread_exit () явно. Все созданные им потоки будут прерваны, потому что main () завершена и больше не существует для поддержки потоков.

Поскольку main () явно вызывает pthread_exit () как последнее, что он делает, main () будет блокироваться и оставаться в живых, чтобы поддерживать созданные им потоки, пока они не будут выполнены.

int main()
    {
         int err;
         pthread_t tid1, tid2;

         err = pthread_create(&tid1, NULL, thread_stuff, (void *)1);
         err = pthread_create(&tid2, NULL, thread_stuff, (void *)1);

         sleep(10);                 /* change the value here if you want */

         /* Add the pthread_exit */     
         pthread_exit(NULL);
         return SUCCESS;
    }

Подробнее см. здесь

...