Alex L
Alex L

Reputation: 115

How to correctly change objects inside a function?

In my application I have a thread run an object's function. In the function some elements of the object are changed, however I am unable to see these changes in my main thread.

I feel like I may not be altering the correct object. Is this accurate?

Thread:

thread_.emplace_back(&Philosopher::Live, philosopher_[i]);

Return:

Philosopher::_state current_state_;
current_state_ = philosopher_[i].ReturnState();

Upvotes: 0

Views: 80

Answers (1)

Tas
Tas

Reputation: 7111

You are likely facing one of two problems*, and without a Minimal, Complete, Verifiable Example I can't tell you for sure which it is.

You are passing a copy

Because there is no context and declaration of philosopher[i] I can't know for sure, but you may be passing a copy. Consider:

struct Philosopher 
{
    void Live();
    int ReturnState();
private:
    int state;
};

std::vector<Philosopher> philosopher_;
philosopher_.emplace_back(...);
std::vector<std::thread> thread_;
thread_.emplace_back(&Philosopher::Live, philosopher_[i]); // A copy of Philosopher is passed
...
int state = philosopher_[i].ReturnState(); // philosopher[i] has not changed.

However, if the std::vector<Philosopher> was a std::vector<Philosopher*> then you would not be passing a copy (hence why it's hard to see without the declaration of philosopher_. If you have declared philosopher_ as a std::vector<Philosopher>, you can fix it with std::ref or by passing a pointer:

std::ref:

std::vector<Philosopher> philosopher_;
...
thread_.emplace_back(&Philosopher::Live, std::ref(philosopher_[i])); // A reference is passed

Pointer:

std::vector<Philosopher> philosopher_;
...
thread_.emplace_back(&Philosopher::Live, &philosopher_[i]); // A pointer is passed

You have not locked your object, and haven't allowed your thread a chance to run

Credit to @deviantfan for pointing out this next point in the comments. Consider:

struct Philosopher 
{
    void Live();
    int ReturnState();
private:
    int state;
};

std::vector<Philosopher> philosopher_;
philosopher_.emplace_back(...);
std::vector<std::thread> thread_;
thread_.emplace_back(&Philosopher::Live, std::ref(philosopher_[i]));
// There is no guarantee that by the time the code reaches here, Philosopher::Live would've had a chance to run and finish.
int state = philospher_[i].ReturnState();

You may not have allowed Philosopher::Live a chance to run and finish. You can deal with this in a multitude of ways, but I will only cover "waiting for the thread to finish".

std::vector<Philosopher> philosopher_;
...
thread_.emplace_back(&Philosopher::Live, std::ref(philosopher_[i]));
thread_[i].lock(); // Wait for the thread to finish
int state = philospher_[i].ReturnState();

This may or may not be desired depending on what you are trying to accomplish. If you want to learn about some other ways, consider reading about std::mutex and std::conditional_variable

*I realise at the time of writing this that you have solved your problem; however, this is just an in-depth answer aimed at helping people with similar problems (plus you may learn something new!) It seems like you may wish to use a mutex to employ thread-safety.

Upvotes: 2

Related Questions