wolf
wolf

Reputation: 127

Protecting C++ classes with pthreads and references

If I have a private member of a class which may be modified by a background thread, and a getter for said private member, can I use a const reference to that private member for the getter or must I protect the getter with a mutex to ensure safety? Here is some example code. Note that I am not using C++11 so I do not have access to those features. I am aware of std::atomic and std::lock_guard and their uses but the code I am working on at this moment uses C++03.

It is worth noting that shared_member's type int is more of a placeholder for simplicity

If there is a nicer way to ensure safety than the get_copyof_shared_int() method, I am all ears. However if the reference will be safe that will also work, I only want to ensure safety.

#include <pthread.h>

using namespace std;

class testclass{

public:

// return reference to shared_member (provided only as example of ideal getter)

    inline const int& get_shared_member () const{
        return shared_member;
    }

// return copy of shared_member (example of getter known to be thread safe )

    inline const int get_copyof_shared_int () {

        pthread_mutex_lock(&shared_int_mutex);

        int shared_member_copy = shared_member;

        pthread_mutex_unlock(&shared_int_mutex);

        return shared_member_copy;

    }

// initializes shared_member and mutex, starts running background_thread
    void init(int);

private:

    volatile int shared_member; //should be marked volatile because it is used in background_thread()

    pthread_mutex_t shared_int_mutex;

    // thread which may modify shared_member 

    static void *background_thread(void *arg);

};

Upvotes: 0

Views: 276

Answers (2)

TypeIA
TypeIA

Reputation: 17248

Unfortunately yes, technically you should protect the getter since int operations are not guaranteed to be atomic.

As for the getter, it looks about as simple as it gets, although I'm not sure why you have two different getters.

EDIT: Don't forget to mark your shared variable as volatile as pointed out in the link above. Otherwise the optimizing compiler may make some improper optimizations since it can assume (wrongly in your case) the variable won't be set by another thread.

Upvotes: 1

kfsone
kfsone

Reputation: 24259

Taking a reference to it is essentially like passing a pointer (references are usually implemented as a contractual layer over pointers).

That means there is no guarantee that your thread won't read the value at some inconvenient time such as when the other thread, on a different core, is in the middle of writing to it.

Also, you might want to look into C++1's and headers.

I would also advise against inlining a getter with a mutex.

const int get_copyof_shared_int () {

    std::lock_guard<std::mutex> lock(shared_int_mutex);

    return shared_int;

}

Upvotes: 1

Related Questions