Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Update if not Expired on Weak Pointer in Multi-Threaded Context

The client holds a shared pointer to a value say double, and a server updates this value on another detached thread by holding a weak_pointer, the server checks if the weak_pointer is expired and if it is not, it is deleted from a safe vector. I suspect this would not work as the shared_ptr could be destructed from the client side between my read of expired() (which I think is thread safe as I imagine it refers to the atomic counter of shared_ptr) and my update of the value. Is there a way to have the check expired() and a lambda function updating the value before it is destructed please? I mean:

struct server
{
public:
    static void subscribe(const std::shared_ptr<double>& d)
    {
        m_values.safe_push_back(d); //safely pushes back in the vector
    }

    void update()
    {
        auto updater = [](std::weak_ptr<double>& wd)
        {
            if(wd.expired()) wd = nullptr;
            else *wd += 2.0; //This is not thread safe I guess?
        };
        m_values.safe_remove_all(nullptr);
        m_values.safe_visit(updater);
    };

private:
    static safe_vector<std::weak_ptr<double>> m_values;
}
struct client
{
    void subcribe_sleep_print(const double random_seconds)
    {
        std::shared_ptr<double> d = std::make_shared<double>(0.0); //for the sake of the example assume we create subscribe before sleep
        server::subscribe(d);
        sleep_for_seconds(random_seconds); //sleeps for some random time in seconds.
        std::cout << *d << std::endl;
    }
}

Imagine server::update and client::subcribe_sleep_print are running on different threads. This is not safe as the shared_ptr might get destructed while the server is writing? Is there a way to this with no user (me) defined atomics or mutexes? I don’t mind if it’s used in the background as long as I don’t add them (atomic/mutex) myself as I know the shared pointer uses an atomic counter already.

EDIT: I am not using double in my program, I am using a thread safe object 🙂 So the operation += can be assumed thread safe. Sorry.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

        else *wd += 2.0; //This is not thread safe I guess?

No, it’s not thread-safe. You are facing a race-condition where the pointer may expire after all just after you have checked for expiration. In that case, you have now dereferenced a nullptr.

So the way to go is to explictly use std::weak_ptr<T>::lock() to try and obtain the associated shared pointer (which is also what expired() did internally), and only if that obtained a valid pointer you may do a read- or write-access.

If you didn’t obtain a valid shared pointer, treat it just as if expired() had returned false.

   m_values.safe_remove_all(nullptr);
   m_values.safe_visit(updater);

I’m certain you’ve got the order wrong. You had intended to first update, and then weed out the nullptr your update callback had produced.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading