Как вернуть значение из потоков pthread в C?
Я новичок в 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:
Согласно первым ответам, проблема в том, что я возвращаю указатель на локальную переменную. Какова наилучшая практика возврата/хранения переменных нескольких потоков? Глобальная хеш-таблица?
Заранее спасибо
Ответы
Ответ 1
Вы возвращаете адрес локальной переменной, которая больше не существует, когда функция потока завершается. В любом случае, зачем вызывать pthread_exit? почему бы просто не вернуть значение из функции потока?
void *myThread()
{
return (void *) 42;
}
а затем в основном:
printf("%d\n",(int)status);
Если вам нужно вернуть сложное значение такой структуры, возможно, проще всего распределить его динамически через malloc() и вернуть указатель. Конечно, код, инициировавший поток, будет отвечать за освобождение памяти.
Ответ 2
Вы вернули указатель на локальную переменную. Это плохо, даже если потоки не задействованы.
Обычный способ сделать это, когда начинающийся поток - это тот же самый поток, который соединяется, должен был передать указатель на int в местоположении, управляемом вызывающим, в качестве 4-го параметра pthread_create. Затем это становится (единственным) параметром для точки входа потока. Вы можете (если хотите) использовать значение выхода потока для указания успеха:
#include <pthread.h>
#include <stdio.h>
int something_worked(void) {
/* thread operation might fail, so here 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;
}
Если вам абсолютно необходимо использовать значение выхода потока для структуры, вам придется динамически распределять его (и убедитесь, что тот, кто присоединяется к потоку, освобождает его). Однако это не идеальное.
Ответ 3
Вот правильное решение. В этом случае 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
Я думаю, вам нужно сохранить номер в куче. Переменная int ret
была в стеке и была разрушена в конце выполнения функции myThread
.
void *myThread()
{
int *ret = malloc(sizeof(int));
if (ret == NULL) {
// ...
}
*ret = 42;
pthread_exit(ret);
}
Не забывайте free
, когда вам это не нужно:)
Другим решением является возвращение числа в качестве значения указателя, как предлагает Neil Butterworth.
Ответ 5
Вы возвращаете ссылку на ret, которая является переменной в стеке.
Ответ 6
#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);
}
Ответ 7
Вопрос: Какова наилучшая практика возврата/хранения переменных нескольких потоков? Глобальная хеш-таблица?
Это полностью зависит от того, что вы хотите вернуть и как вы его используете? Если вы хотите вернуть только статус потока (скажите, завершил ли поток то, что он намеревался сделать), просто используйте pthread_exit или используйте оператор return, чтобы вернуть значение из функции потока.
Но, если вам нужна дополнительная информация, которая будет использоваться для дальнейшей обработки, вы можете использовать глобальную структуру данных. Но в этом случае вам придется обрабатывать проблемы concurrency, используя соответствующие примитивы синхронизации. Или вы можете выделить некоторую динамическую память (желательно для структуры, в которой вы хотите сохранить данные), и отправить ее через pthread_exit, и как только поток присоединяется, вы обновляете его в другой глобальной структуре. Таким образом, только один основной поток будет обновлять глобальную структуру, а проблемы concurrency будут устранены. Но вам нужно обязательно освободить всю память, выделенную различными потоками.
Ответ 8
если вам неудобно возвращать адреса и иметь только одну переменную, например. целочисленное значение для возврата, вы можете даже приписать его в (void *) перед его передачей, а затем, когда вы соберете его в основном, снова введите его в (int). У вас есть значение, не вызывая уродливых предупреждений.