Home > Back-end >  Is it "correct" to specify class-member mutex 'mutable' for the purpose of much-
Is it "correct" to specify class-member mutex 'mutable' for the purpose of much-

Time:12-27

In many cases, many member-functions could be specified 'const' - they don't modify any data-members of the class ...almost: they do lock/unlock the class mutex. Is it a good practice to specify, in that case, the mutex 'mutable'? ...otherwise, it will impossible to specify get_a(), get_b(), get_c(), get_d() 'const'.

--

A mere example. Lets say that 'example' is a thread-safe class and that m_mutex protects its shared resources that get_a(), get_b(), get_c(), get_d() do not modify:

#include <mutex>

class example
{
public:
    size_t get_a(void) const {
        std::lock_guard lck(m_mutex);
        return m_str.length()   a;
    };

    size_t get_b(void) const {
        std::lock_guard lck(m_mutex);
        return m_str.length() * 2   a   b;
    };

    size_t get_c(void) const {
        std::lock_guard lck(m_mutex);
        return m_str.length() * 4   a   b;
    };

    size_t get_d(void) const {
        std::lock_guard lck(m_mutex);
        return m_str.length() * 8   a;
    };

    void modify_something() {
        std::lock_guard lck(m_mutex);
        if (m_str.length() < 1000) {
            m_str.append(".");
            a  ;
            b  ;
        }
    };

protected:
    mutable std::mutex m_mutex;
    std::string m_str;
    int a = 0, b = 0;
};

CodePudding user response:

Yes, it’s common to make synchronization objects mutable for exactly this reason. With that said, it’s also relatively uncommon to have those synchronization objects held inside the class, as “ensure safe concurrency” is rarely something that the class itself is about.

CodePudding user response:

Not only is this correct, but also standard practice. A member mutex is described as "non observably non-const", which means it behaves as a constant to a "user" observer.

Herb Sutter has popularized the M&M rule:

For a member variable, mutable and mutex (or atomic) go together.

The rule's section related to your question states:

For a member variable, mutex (or similar synchronization type) implies mutable: A member variable that is itself of a synchronization type, such as a mutex or a condition variable, naturally wants to be mutable, because you will want to use it in a non-const way (e.g., take a std::lock_guard<mutex>) inside concurrent const member functions.

The linked article has many code examples and further elaboration, should you want to dive deeper.

  • Related