Как вернуть значение из потоков pthread в C? - PullRequest
44 голосов
/ 12 февраля 2010

Я новичок в C и хотел бы немного поиграть с потоками. Я хотел бы вернуть некоторое значение из потока, используя pthread_exit()

Мой код выглядит следующим образом:

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

void *myThread()
{
   int ret = 42;
   pthread_exit(&ret);
}

int main()
{
   pthread_t tid;
   void *status;

   pthread_create(&tid, NULL, myThread, NULL);
   pthread_join(tid, &status);

   printf("%d\n",*(int*)status);   

   return 0;
}

Я ожидаю, что программа выдаст «42 \ n», но она выдаст случайное число. Как я могу напечатать возвращаемое значение?

EDIT: Согласно первым ответам проблема в том, что я возвращаю указатель на локальную переменную. Какова лучшая практика возврата / хранения переменных нескольких потоков? Глобальная хеш-таблица?

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

Ответы [ 8 ]

42 голосов
/ 12 февраля 2010

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

void *myThread()
{
   return (void *) 42;
}

и затем в основном:

printf("%d\n",(int)status);   

Если вам нужно вернуть сложное значение, такое как структура, вероятно, проще всего динамически выделить его через malloc () и вернуть указатель. Конечно, код, который инициировал поток, будет отвечать за освобождение памяти.

25 голосов
/ 12 февраля 2010

Вы вернули указатель на локальную переменную. Это плохо, даже если потоки не задействованы.

Обычный способ сделать это, когда запускаемый поток - это тот же поток, который присоединяется, - передать указатель на int в местоположении, управляемом вызывающей стороной, в качестве 4-го параметра pthread_create. Затем он становится (единственным) параметром для точки входа потока. Вы можете (если хотите) использовать значение выхода из потока, чтобы указать успех:

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

int something_worked(void) {
    /* thread operation might fail, so here's a silly example */
    void *p = malloc(10);
    free(p);
    return p ? 1 : 0;
}

void *myThread(void *result)
{
   if (something_worked()) {
       *((int*)result) = 42;
       pthread_exit(result);
   } else {
       pthread_exit(0);
   }
}

int main()
{
   pthread_t tid;
   void *status = 0;
   int result;

   pthread_create(&tid, NULL, myThread, &result);
   pthread_join(tid, &status);

   if (status != 0) {
       printf("%d\n",result);
   } else {
       printf("thread failed\n");
   }

   return 0;
}

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

21 голосов
/ 17 ноября 2013

Вот правильное решение. В этом случае tdata размещается в основном потоке, и у потока есть место для размещения его результата.

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

typedef struct thread_data {
   int a;
   int b;
   int result;

} thread_data;

void *myThread(void *arg)
{
   thread_data *tdata=(thread_data *)arg;

   int a=tdata->a;
   int b=tdata->b;
   int result=a+b;

   tdata->result=result;
   pthread_exit(NULL);
}

int main()
{
   pthread_t tid;
   thread_data tdata;

   tdata.a=10;
   tdata.b=32;

   pthread_create(&tid, NULL, myThread, (void *)&tdata);
   pthread_join(tid, NULL);

   printf("%d + %d = %d\n", tdata.a, tdata.b, tdata.result);   

   return 0;
}
4 голосов
/ 12 февраля 2010

Я думаю, вы должны хранить номер в куче. Переменная int ret была в стеке и была уничтожена в конце выполнения функции myThread.

void *myThread()
{
       int *ret = malloc(sizeof(int));
       if (ret == NULL) {
           // ...
       }
       *ret = 42;
       pthread_exit(ret);
}

Не забудьте free, когда вам это не нужно:)

Другое решение - вернуть число в качестве значения указателя, как предлагает Нил Баттерворт.

2 голосов
/ 18 ноября 2014
#include<stdio.h>
#include<pthread.h>
void* myprint(void *x)
{
 int k = *((int *)x);
 printf("\n Thread created.. value of k [%d]\n",k);
 //k =11;
 pthread_exit((void *)k);

}
int main()
{
 pthread_t th1;
 int x =5;
 int *y;
 pthread_create(&th1,NULL,myprint,(void*)&x);
 pthread_join(th1,(void*)&y);
 printf("\n Exit value is [%d]\n",y);
}  
2 голосов
/ 12 февраля 2010

Вы возвращаете ссылку на ret , которая является переменной в стеке.

1 голос
/ 12 февраля 2010

Вопрос: Каков наилучший метод возврата / хранения переменных нескольких потоков? Глобальная хеш-таблица?

Это полностью зависит от того, что вы хотите вернуть и как вы будете его использовать? Если вы хотите вернуть только состояние потока (скажем, завершил ли поток то, что он намеревался сделать), тогда просто используйте pthread_exit или оператор return, чтобы вернуть значение из функции потока.

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

0 голосов
/ 08 октября 2011

, если вам неудобно возвращать адреса и у вас есть только одна переменная, например. целочисленное значение, которое нужно вернуть, вы можете даже ввести его в (void *) перед его передачей, а затем, когда вы соберете его в main, снова ввести его в (int). У вас есть значение, не выбрасывая уродливые предупреждения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...