Pregunta

After reading this thread: How to return a value from thread in C on how to return an integer value from a pthread I tested to see if it could work for a double, but it didn't. Is there a way to return a double, long or a string from the pthread process like described in the original thread instead of returning the integer number 42?

If yes how?

And if I have a static array of 10 positions and 10 pthreads modifiying different positions each time, will I have trouble? AN example would be like "thread 0 modifies only array[0], thread 1 modifies only array[1] and so on".

¿Fue útil?

Solución 2

These are just reformulations of Steve Jessop's C solution into C++. These toy examples (note the lack of error checking) use templates to make it obvious how to change the code to use some type other than double. For example, the double could be replaced with a class type if more than one value needed to be returned after the work is done. In practice, the base class and template would likely be removed and the work() method of MyWorker would be called directly by the invoker rather than via a virtual method.

First, using 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;
}

Second, using 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;
}

You had another question in your post that I had missed:

And if I have a static array of 10 positions and 10 pthreads modifiying different positions each time, will I have trouble?

Whether or not this gives you trouble will likely depend on the array element type and your hardware architecture. In practice, I have not observed this being a problem on x86 architectures for array elements that are aligned on machine word boundaries.

Otros consejos

The thread just has to dynamically allocate memory for the result you want it to return:

void *myThread(void*)
{
   double* result = (double*) malloc(sizeof(double));

   *result = 42.0;

   return result;
}

Whatever is supposed to collect that result dereferences the pointer returned using an appropriate cast (this is C with void* after all), then free the memory:

// 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);

As an alternative, whatever creates the thread can pass a pointer to where the thread should put it's result in the void* parameter to the thread (possibly as part of a struct if the thread needs more than just that bit of information). That might allow you to avoid dynamic memory allocation if you have a reason to avoid that, but it might make ownership and lifetime of the data somewhat more complicated to manage.

I don't think this is too hard. I don't use malloc(size_t) from cstdlib, but just new. The following example passes an argument to the thread as struct and returns another struct as well. To show it can take any variable type I also used vectors of strings...

#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;
}    
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top