MFC Grid manual

Thread protection of a C++ object

// The declaration of the class, an instance of which can be directly 
// inserted into the grid. 
// The grid itself can consume a notification from any thread and this example 
// demonstrates how to do thread-safe implementation of CMyClass.


// MyClass.h file
class CMyClass : public Dapfor::Common::CDataObject
{
public:
    // It is better to use enumerations instead of long-type numeric values...
    // The grid can use the same identifiers to show the values returned 
    // by the functions of this class.
    enum
    {
        FidPrice,
        ...
    };

public:

    //Get- methods
    double  GetPrice() const;
    ...

    //Set- methods
    void  SetPrice(double newPrice);
    ...


private:
    double  m_Price;
    ...

    //Declare the critical section that is used in get & set methods
    mutable Dapfor::Common::CSyncObject m_Sync;


    //Declaration of the map, that contains a list of the functions, 
    //that can be called by their identifiers.
    DF_DECLARE_FIELD_MAP();
};




//MyClass.cpp file


// Declaration of a field map.
// To put an object of CMyClass into grid, it should declare the table, 
// which permits to call specified functions by its identifiers. 
// Also, we can customize a presentation using the formats, included in Common 
// library or our custom formats.
DF_BEGIN_FIELD_MAP(CMyClass)
    DF_DOUBLE_ID(FidPrice,    "Price",    &CMyClass::GetPrice,    &CMyClass::SetPrice, 0)
    ...
DF_END_FIELD_MAP()


// This Get- method can be called in any thread and we need protect
// internal members of CMyClass object.
double  CMyClass::GetPrice() const
{
    //Protect m_Price value
    Dapfor::Common::CLock lock(m_Sync);
    return m_Price;
}

...

//This method can be called in any thread and we need protect object's members.
void  CMyClass::SetPrice(double newPrice)
{
    // This method is a little bit long, but it protects well m_Price value 
    // and excludes dead-lock possibility between two or more threads.
    // The main rule: don't call any external methods (NotifyUpdate for example)    
    // while taking a synchronization object. 

    // sendNotification value is placed in stack and doesn't need to be protected.
    bool sendNotification = false;
    {
        //Protect m_Price value
        Dapfor::Common::CLock lock(m_Sync);
        if(m_Price != newPrice)
        {
            m_Price = newPrice;
            sendNotification = true;
        }
    }

    // Check if there are any modifications.
    if(sendNotification)
    {
        //Send a notification without lock.
        NotifyUpdate(FidPrice);
    }
}