Grego
Grego

Reputation: 2250

pthread accessing it from a Class, variables are lost, when directly works fine

Well I'm trying to set a variable to use in a thread, it works fine if I call the pthread from the main function, but if I call it from a function or a function inside a class, the variable is lost and prints garbage instead, that's why I added the condition

if(this->pickup < 7)

so I minimized the code so I could post it here because it has all the examples I'm saying.

The output of this code below is:

Access by Class:

Hello, world! <

Access Directly:

Hello, world!, N: 6<

I would like to have the same result as in Access Directly in Access by Class, I want it to output the ", N: 6" because after all it was defined. what am I missing here?

I hope I was clear enough, thanks in advance.

(By the way, I'm using the pthread library that is available for windows) so here is the code:

#include <stdio.h>
#include <pthread.h>
#include <iostream>
#include <conio.h>
#include <windows.h>

class C {
public:
    int pickup;

    void *hello()
    {
        std::cout << "\nHello, world!";

        if(this->pickup < 7)
        std::cout << ", N: " << this->pickup;

        std::cout << "<" << std::endl;
        printf("HI");
        return 0;
    }

    static void *hello_helper(void *context)
    {
        return ((C *)context)->hello();
    }


    void StartThread(){
        C c;
        c.pickup = 6;

        pthread_t t;
        pthread_create(&t, NULL, &C::hello_helper, &c);
    }


};



int main () {

    C c;
    std::cout << "Access by Class: \n";
    c.StartThread();
    c.pickup = 6;
    Sleep(2000);

    std::cout << "\nAccess Directly: \n";
    pthread_t t;
    pthread_create(&t, NULL, &C::hello_helper, &c);

    _getch();
    return 0;
}

Upvotes: 2

Views: 1582

Answers (4)

Kaz
Kaz

Reputation: 58578

Note that StartThread creates a C object which is produced neither from any argument material (StartThread takes no arguments) nor from any member material of the classt of which StartThread is a member. I.e you can have this:

void StartThread(){
    pthread_t t;
    pthread_create(&t, NULL, &C::hello_helper, NULL);
}

// The code is easily moved into the thread.
static void hello_helper(void *)
{
   C c;
   c.pickup = 6;

}

Furthermore, is it possible that you actually wanted this?

void StartThread(){
    pthread_t t;
    pickup = 6;
    // use THIS object, not some new one, doh?
    pthread_create(&t, NULL, &C::hello_helper, (void *) this);
}

I.e. maybe you actually want obj.StartThread() to start a thread which works with obj rather than creating some other object internally?

Upvotes: 0

hmjd
hmjd

Reputation: 121971

c is destroyed when StartThread() returns, meaning hello_helper() is using a dangling pointer resulting in undefined behaviour.

Change to:

void StartThread(){
    C* c = new C();
    c->pickup = 6;

    pthread_t t;
    pthread_create(&t, NULL, &C::hello_helper, c);
}

Remember to delete the argument passed into hello_helper():

static void *hello_helper(void *context)
{
    C* c = static_cast<C*>(context);
    c->hello();
    delete c;
    return 0;
} 

EDIT:

Always deleteing the argument passed into hello_helper() would prevent passing stack allocated objects into hello_helper(). A mechanism is required to instruct hello_helper() whether it is responsible for destructing its argument.

Upvotes: 2

Jason
Jason

Reputation: 32510

The call to pthread_create() returns instantly, therefore you exit from the C::StartThread function before your spawned thread really has a chance to run. Thus the C instance object represented by c doesn't exist anymore since it was an automatic variable on the stack of StartThread. You need to make sure the life-time of c exists beyond the stack of StartThread, which is typically done using dynamic memory, or possibly a static variable, etc.

Upvotes: 0

Collin
Collin

Reputation: 12287

The C you're starting the thread with in StartThread() goes out of scope and is destructed before the thread you are creating has a chance to use it.

If you know the class instance you're calling StartThread() on will exist for the life of the thread, perhaps you want to pass this as the context rather than a new stack object:

void StartThread() {
    pthread_t t;
    pthread_create(&t, NULL, &C::hello_helper, this);
}

Upvotes: 1

Related Questions