C++ 作用域互斥锁

C++ 作用域互斥锁,c++,c++11,mutex,raii,C++,C++11,Mutex,Raii,我以前从未真正使用过互斥体,但我需要控制对受保护资源的访问。通过浏览新的C++11内容,我编写了以下类: class CMutex { public: class Lockable { friend class CMutex; std::atomic_flag flag; public: Lockable() { flag.clear(); } }; priva

我以前从未真正使用过互斥体,但我需要控制对受保护资源的访问。通过浏览新的C++11内容,我编写了以下类:

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 ...
    }
}
这样的用法:

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

        // do stuff
        ...

        // mutex should automagically be RAII released here
    }
    ...
};
首先,我感兴趣的是这个概念是否实际有效(考虑到std::atomic等的实现),它应该如何工作

其次,我注意到它正确地获得了锁,但是它立即释放了锁。我想我应该给锁起个名字

CMutex lock(this);
然而,如果编译器可以保证我不会与对象进行更多的交互,那么在将作用域作为优化之前,它不是可以自由地销毁对象吗?如果我不能保证析构函数只在作用域出口被调用,那么这将破坏这个构造的目的


关于

这里有一个技巧可能对您很方便,它适用于所有主流(VC++、clang、gcc)编译器:

#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
    }

不,编译器不能在作用域结束前自由销毁

标准部分124/10
-对于创建对象的块退出时具有自动存储持续时间(3.7.3)的构造对象。

CMutex(此)
是临时的,仅持续到完整表达式结束(即分号之前),然后将其销毁。当你给它命名时,它会变成一个自动变量,并在作用域的末尾被销毁。自C++11以来,标准库中就已经有了。@Simple Yes,我想是的,但最后一条评论(问题3?)如何?我知道SNP,但我可能需要将其扩展到没有C++11的平台,这只是一个简单的例子prototype@Shaggi没有在作用域末尾调用的析构函数以及更早调用的析构函数将违反“好像”规则,因为它可以让代码观察到这一点。不允许编译器执行该优化。@沙吉:如果需要使用C++11之前的版本,则不应使用C++11功能。或者根据std::mutex实现这个类,这样做是正确的;或者调用特定于平台的锁。或者使用boost::thread。或类似的。发明自己的锁会带来灾难。谢谢,我只想知道!这不会生成形式为
\uuuuu scoped\u lockXY
的名称吗?这些名称不是编译器实现的保留标识符吗?您可以用任何需要的名称替换“\uuuu scoped\u lock”。我通常生成以“\ux”开头的名称,以从我的VAssistX自动完成工具中隐藏这些名称。无论如何,从一些私有框架变量/类型名开始,加上“u”是可以的。隐藏这些名称似乎很方便,但它会调用未定义的行为:@pasztorpisti:不,不。您的工具链已经保留了它们。使用
详细信息
名称空间。@stefan谢谢你提供的信息,我不知道。具有讽刺意味的是,我正在处理massive/hugh代码库,实际上,我在任何主要编译器(VC、clang、gcc)上都没有遇到过这样的问题。也许这只是因为下划线计数与字母大小写和/或其他因素(如范围)的正确组合带来的运气…:-)好的,我修复了答案中的变量名。