locking class members from other threads

Viewed 514

I need to lock private class member for other threads: if i do not unlock variable, other threads can not use that variable, and wait before it unlocks. (something like mutex).

For example:

using namespace std;
class a
{
public:
    a() {
    //here i need to lock my variable
    thread th([this] {
    Sleep(10000);
    variable = 100;});
    //here i need to unlock my variable});

    }

    int getVariable() { return this->variable; }

private:
    int variable;
};



int main() {
    a var;

    thread th([&var] {cout << var.getVariable() << endl; });
    //getVariable waits before variable is unlocked
}
1 Answers

You can't lock arbitrary variables. What you need to do is guard access to your shared variable using a mutex or other synchronization object. For example:

class a
{
public:
    a() {
        std::thread th([this] {
            std::lock_guard lock(variable_mutex);
            std::this_thread::sleep_for(std::chrono::milliseconds(10000));
            variable = 100;
        });
        th.detach(); // you probably actually want to store th somewhere instead
    }

    int getVariable() {
        std::lock_guard lock(variable_mutex);
        return this->variable;
    }

private:
    int variable;
    std::mutex variable_mutex;
};

int main() {
    a var;
    std::cout << var.getVariable() << '\n';
}

Live Demo

This will prevent both the main thread and the thread started in a's constructor from accessing variable at the same time. The demo I included highlights a problem with this though. It's possible that the main thread could lock the mutex before the thread that initializes it. If this is a problem in your case, you could instead use an event/flag class. The standard library doesn't provide one, but it's possible to build one out of a mutex and a condition variable:

class Event
{
public:
    Event()
        : is_set{false}
    {
    }

    void set()
    {
        std::unique_lock lock(mutex);
        is_set = true;
        cond_var.notify_all();
    }

    void wait()
    {
        std::unique_lock lock(mutex);
        cond_var.wait(lock, [this]() { return is_set; });
    }

private:
    bool is_set;
    std::mutex mutex;
    std::condition_variable cond_var;
};

class a
{
public:
    a() {
        std::thread th([this] {
            std::this_thread::sleep_for(std::chrono::milliseconds(10000));
            variable = 100;
            variable_initialized.set();
        });
        th.detach(); // you probably actually want to store th somewhere instead
    }

    int getVariable() {
        variable_initialized.wait();
        return variable;
    }

private:
    int variable;
    Event variable_initialized;
};

int main() {
    a var;
    std::cout << var.getVariable() << '\n';
}

Live Demo

Note that this flag-based approach only works if, as in the example, variable is only written to once. Some other approach would be needed if it's possible for variable to change later. In the end, the exact type of synchronization needed will depend on the specifics of your situation. There are many ways to synchronize access to data across threads, and that's one of the things that makes writing multithreaded programs challenging.

Related