Scoped mutex lock

2019-09-09 09:54发布

问题:

I never really worked with mutexes before, but i need to control access to protected resources. Looking through the new C++11 stuff, i cooked up this class:

class CMutex
{
public:
    class Lockable
    {
        friend class CMutex;
        std::atomic_flag flag;
    public:
        Lockable()
        {
            flag.clear();
        }
    };
private:
    Lockable * resource;
    CMutex(const CMutex &);
public:
    CMutex(Lockable * l)
    {
        resource = l;
        acquire(l);
    }
    CMutex(Lockable & l)
    {
        resource = &l;
        acquire(l);
    }
    CMutex()
        : resource(nullptr)
    {
    }
    ~CMutex()
    {
        if (resource)
            release(resource);
    }
    void acquire(Lockable * l)
    {
        if (!resource)
            resource = l;
        if (!spinLock(2000, resource))
            //explode here
            return;
    }
    void acquire(Lockable & l)
    {
        acquire(&l);
    }
private:
    void release(Lockable * l)
    {
        if (l)
            l->flag.clear();

    }
    static bool spinLock(int ms, Lockable *  bVal)
    {
        using namespace Misc;
        long start;
        int ret;
    loop:
        start = QuickTime();
        while (bVal->flag.test_and_set()) {
            if ((QuickTime() - start) > ms)
                goto time_out;
            // yield thread
            Delay(0);
        }
        // normal exitpoint
        return true;
        // deadlock occurs
    time_out:
        // handle error ...
    }
}

Usage like so:

class MyClass : public CMutex::lockable
{
    ...
    void doStuff()
    {
        // lock data
        CMutex(this);

        // do stuff
        ...

        // mutex should automagically be RAII released here
    }
    ...
};

First of all, I'm interested in whether this concept actually works how it should (given the implementation of std::atomic etc.)?

Secondly, I noticed that it correctly obtains the lock, however it releases it instantly. I guess i should give the lock a name?

CMutex lock(this);

However, isn't the compiler free to destruct the object before the scope is left as an optimization provided it can guarantee that i wont interact more with the object? This would defeat the purpose of this construct, if i can't guarantee that the destructor only will be called at scope exit.

Regards

回答1:

No, the compiler is not free to destruct before the scope ends.

Per the C++ Standard section 12.4/10 — for constructed objects with automatic storage duration (3.7.3) when the block in which an object is created exit.



回答2:

Here is a trick that may come handy for you and it works with all mainstream (VC++, clang, gcc) compilers:

#define APPEND_ID1(id1, id2) id1##id2
#define APPEND_ID2(id1, id2) APPEND_ID1(id1, id2)
#define APPEND_COUNTER(id) APPEND_ID2(id, __COUNTER__)

#define SCOPED_LOCK(lockable) CMutex APPEND_COUNTER(scoped_lock)(lockable)

class MyClass : public CMutex::lockable
{
    ...
    void doStuff()
    {
        // lock data
        SCOPED_LOCK(this);
        // auto-generates a unique name, works even with multiple locks in the same scope..
        SCOPED_LOCK(that);

        // do stuff
        ...

        // mutex should automagically be RAII released here
    }