Прочитав эту ветку: Как вернуть значение из потока в C о том, как вернуть целочисленное значение из pthread, которое я тестировал, чтобы увидеть, может ли оно работать на удвоение, но это не сработало. Есть ли способ вернуть double, long или строку из процесса pthread, как описано в исходном потоке, вместо возврата целого числа 42?
Если да, то как?
И если у меня будет статический массив из 10 позиций и 10 потоков, каждый раз меняющий разные позиции, у меня будут проблемы?
Пример AN выглядит как «поток 0 изменяет только массив [0], поток 1 изменяет только массив [1] и т. Д.».
Это просто переформулировки Решение Стив Джессоп С в C ++. В этих игрушечных примерах (обратите внимание на отсутствие проверки ошибок) используются шаблоны, чтобы понять, как изменить код, чтобы использовать какой-либо другой тип, кроме double
, Например, double
может быть заменен на class
введите, если более чем одно значение необходимо вернуть после выполнения работы. На практике базовый класс и шаблон, скорее всего, будут удалены, а work()
метод MyWorker
будет вызываться непосредственно вызывающим, а не через виртуальный метод.
Во-первых, используя pthread
:
#include <iostream>
#include <pthread.h>
class WorkerBase {
protected: virtual ~WorkerBase () {}
public: virtual void * work () = 0;
};
template <typename T>
struct Worker : public WorkerBase { T result; };
extern "C" void *invoke_worker (void *arg) {
return static_cast<WorkerBase *>(arg)->work();
}
struct MyWorker : public Worker<double> {
void * work () {
result = 4.2;
return 0;
}
};
int main () {
pthread_t t;
MyWorker w;
pthread_create(&t, 0, invoke_worker, &w);
pthread_join(t, 0);
std::cout << "result: " << w.result << std::endl;
return 0;
}
Во-вторых, используя C ++ 11 std::thread
:
#include <iostream>
#include <thread>
class WorkerBase {
protected: virtual ~WorkerBase () {}
public: virtual void work () = 0;
static void invoke (WorkerBase *w) { w->work(); }
};
template <typename T>
struct Worker : public WorkerBase { T result; };
class MyWorker : public Worker<double> {
void work () { result = 4.2; }
};
int main () {
MyWorker w;
std::thread t(MyWorker::invoke, &w);
t.join();
std::cout << "result: " << w.result << std::endl;
return 0;
}
У вас был другой вопрос в вашем посте, который я пропустил:
И если у меня будет статический массив из 10 позиций и 10 потоков, каждый раз меняющий разные позиции, у меня будут проблемы?
Будет ли это доставлять вам неприятности, скорее всего, будет зависеть от типа элемента массива и вашей аппаратной архитектуры. На практике я не заметил, чтобы это было проблемой в архитектурах x86 для элементов массива, которые выровнены по границам машинных слов.
Поток просто должен динамически распределять память для результата, который вы хотите вернуть:
void *myThread(void*)
{
double* result = (double*) malloc(sizeof(double));
*result = 42.0;
return result;
}
Что бы ни предполагалось собирать, этот результат разыменовывает указатель, возвращенный с использованием соответствующего преобразования (это C с void*
в конце концов), то освободите память:
// calling thread (or whatever will collect the value)
void* thread_result;
int err = pthread_join( thread_handle, &thread_result);
double dbl = *(double*) thread_result;
free(thread_result);
В качестве альтернативы, все, что создает поток, может передать указатель туда, где поток должен поместить свой результат в void*
параметр потока (возможно, как часть структуры, если потоку требуется больше, чем просто бит информации). Это может позволить вам избежать динамического выделения памяти, если у вас есть причина этого избежать, но это может сделать владение и время жизни данных несколько более сложным в управлении.
Я не думаю, что это слишком сложно. Я не использую malloc (size_t) из cstdlib, но только новый.
В следующем примере аргумент передается потоку как структура, а также возвращается другая структура. Чтобы показать это можно взять любой тип переменной, я также использовал векторы строк …
#include <iostream>
#include <pthread.h>
#include <vector>
#include <string.h>
#include <cstdlib>
using namespace std;
struct thread_data {
int number;
vector<string> strings;
thread_data (){}
thread_data(int nr) {
number = nr;
strings.push_back("aba\n");
}
};
struct thread_return_data {
int S;
vector<string> R;
};
void *Thread (void *threadarg) {
thread_return_data *R = new thread_return_data;
thread_data * Q;
Q = (thread_data *) threadarg;
cout << Q->number << endl;
R->S = 16; //random number
R->R.push_back("14fjnv"); //random string
R->R.push_back("28jfhn"); //random string
pthread_exit(R);
return 0;
}
int main() {
thread_data A(4444); //initialize with random int
thread_return_data *B; //is pointer
pthread_t aThread; //is variable
pthread_create(&aThread, NULL, Thread, (void *)&A);
pthread_join(aThread, (void **)&B);
cout << B->S << endl;
cout << B->R[0] << endl;
cout << B->R[1] << endl;
cout << A.strings[0];
delete B;
return 0;
}