关于CRITICAL_SECTION用法的问题

q09*_*987 2 c++ winapi visual-c++

鉴于以下代码,

class MyCriticalSection : protected CRITICAL_SECTION
{
public:
    MyCriticalSection()
    {
        InitializeCriticalSection(this);
        EnterCriticalSection(this);
    }
    ~MyCriticalSection()
    {
        LeaveCriticalSection(this);
        DeleteCriticalSection(this);
    }
};

class MyClass
{
public:
    MyClass() : m_Int(0) {}

    int GetNum() 
    { 
        MyCriticalSection myCriticalSectionA;  // LockA

        return m_Int; 
    }

    int SetNum(int i)
    {
        MyCriticalSection myCriticalSectionB;  // LockB

        m_Int = i;
    }
protected:
    int m_Int;
};
Run Code Online (Sandbox Code Playgroud)

我认为上面的设计是正确的,如果你发现一些错误,请纠正我.LockA的使用有两个功能:1>它可以防止多个线程同时调用GetNum函数.2>它阻止GetNum和SetNum函数同时访问m_Int.

这是我的问题:变量myCriticalSectionA和myCriticalSectionB是MyCriticalSection类的两个不同实例.为什么他们可以相互协作,以便锁定机制按预期工作?

我的猜测是,CRITICAL_SECTION不知何故有一些静态标志,以便它的不同实例可以相互通信.

如果我错了,请纠正我.

====更新====

class MyCriticalSection : protected CRITICAL_SECTION
{
public:
    MyCriticalSection()
    {
        InitializeCriticalSection(this);

    }
    ~MyCriticalSection()
    {       
        DeleteCriticalSection(this);
    }
    void Lock()
    {
        EnterCriticalSection(this);
    }
    void UnLock()
    {
        LeaveCriticalSection(this);
    }
};

class MyClass
{
public:
    MyClass() : m_Int(0) {}

    int GetNum() 
    { 
        m_Lock.Lock();
        // do something here
        m_Lock.UnLock();
        return m_Int; 
    }

    int SetNum(int i)
    {
        m_Lock.Lock();      
        m_Int = i;
        m_Lock.UnLock();
    }
protected:
    int m_Int;
    MyCriticalSection m_Lock;
};
Run Code Online (Sandbox Code Playgroud)

谢谢

Dav*_*nan 6

您的更新并不是更好.如果你想以RAII风格做到这一点,那么你需要更努力地工作.关键是您需要将静态分配的临界区对象与需要保护的所有块的本地锁分开.

以下是Jonathan Dodds解除的,但这是一个经典的模式.

class CriticalSection
{
public:
    CriticalSection()
        { ::InitializeCriticalSection(&m_rep); }
    ~CriticalSection()
        { ::DeleteCriticalSection(&m_rep); }

    void Enter()
        { ::EnterCriticalSection(&m_rep); }
    void Leave()
        { ::LeaveCriticalSection(&m_rep); }

private:
    // copy ops are private to prevent copying
    CriticalSection(const CriticalSection&);
    CriticalSection& operator=(const CriticalSection&);

    CRITICAL_SECTION m_rep;
};
Run Code Online (Sandbox Code Playgroud)

虽然你可以通过继承CRITICAL_SECTION来做到这一点,但我觉得封装更合适.

接下来定义了锁定:

class CSLock
{
public:
    CSLock(CriticalSection& a_section)
        : m_section(a_section) { m_section.Enter(); }
    ~CSLock()
        { m_section.Leave(); }

private:
    // copy ops are private to prevent copying
    CSLock(const CSLock&);
    CSLock& operator=(const CSLock&);

    CriticalSection& m_section;
};
Run Code Online (Sandbox Code Playgroud)

最后,一个用法示例:

class Example
{
public:
    bool Process( … );

    …

private:
    CriticalSection m_criticalsection;

    …
};

bool Example::Process( … )
{
    CSLock lock(m_critsection);

    // do some stuff
    …
}
Run Code Online (Sandbox Code Playgroud)

关键是在所有线程中共享一个关键部分的单个实例.这就是使关键部分有效的原因.

在相反的情况下CSLock,可能存在许多同时存在的同一临界区的实例.这允许该Process()方法被许多线程调用,但其代码CSLock在单个共享临界区上采用的实例的生命周期内被序列化.