    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Enlarging on &quot;A Problem of Access&quot; in C Vu December 2001
Volume 13 Number 6</title>
        <link>https://members.accu.org/index.php/articles/1196</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>




<div class="xar-mod-head"><span class="xar-mod-title">Programming Topics + CVu Journal Vol 14, #5 - Oct 2002</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c65/">Programming</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c77/">CVu</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c112/">145</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/c65-112/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/articles/c65+112/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Enlarging on &quot;A Problem of Access&quot; in C Vu December 2001
Volume 13 Number 6</h1>
<p><strong>Author:</strong>&nbsp;</p>
<p>
<strong>Date:</strong> 03 October 2002 13:15:54 +01:00 or Thu, 03 October 2002 13:15:54 +01:00</p>
<p><strong>Summary:</strong>&nbsp;</p>
<p><strong>Body:</strong>&nbsp;<p>We are developing a component based system where one central
component is the server.</p>
<p>Among other things, the server holds some very large containers
of objects (thus these containers are preferably constructed only
once - at the time the server component is coming up.) A number of
client components can refer to the container object simultaneously.
They may inspect it (<span class="emphasis"><em>shared</em></span>
mode - container and its objects are read only) when there are no
<span class="emphasis"><em>exclusive</em></span> (<span class=
"emphasis"><em>mutating</em></span>) mode clients, but if any
client wants to change any such containers or objects within, it
has to have an exclusive lock on the container first (<span class=
"emphasis"><em>exclusive</em></span> or <span class=
"emphasis"><em>mutating</em></span> mode ) and there must be no
pre-existing <span class="emphasis"><em>exclusive</em></span> or
<span class="emphasis"><em>shared</em></span> mode clients. This
way, there is no (meaning &quot;minimum&quot;!) space for surprises.</p>
<p>One such container is <tt class="literal">Dimension</tt>, which
holds a great many members (millions). The following abstract class
is exposed to outside clients (other components):</p>
<pre class="programlisting">
// Interface class 
class CDimension_I { 
  public: 
    virtual Id GetId() = 0; 
    virtual void setId(Id id) = 0; 
    // other interface methods 
};
// This class holds millions of members organized in a tree structure 
class CBaseDimension : public CDimension_I, public Resource_m { 
  public: 
    Id GetId(); 
    void setId(Id id); 
    //other helpers and concrete implementations 
}; 
</pre>
<p>Client contexts are stored in objects of class Session.</p>
<pre class="programlisting">
CBaseDimension&amp; cbd = ...; 
Session* pSession = ...; 
// ... 
ResLock_m* pResLock = new ResLock_m( 
    dynamic_cast&lt;Resource_m*&gt;(&amp;cbd),
    pSession,
    LT_SHARED); //locks in shared mode 
// inspect the container, traverse the data structures it holds etc. 
delete pResLock; // unlock the above locked resource 
</pre>
<p>A number of issues rear their ugly heads:</p>
<div class="orderedlist">
<ol type="1">
<li>
<p>How can we handle locking transparently? The business logic gets
muddled if we put locking calls in between.</p>
</li>
<li>
<p>How do we make sure that every Resource is locked, used and
released? (i.e., no resource leaks).</p>
</li>
<li>
<p>What about multiple locking of the same resource by the same
client?</p>
</li>
</ol>
</div>
<p>Okay, let us take them in turn. First some definitions:</p>
<pre class="programlisting">
enum LOCK_TYPE { 
  LT_NOLOCK, 
  LT_EXCLUSIVE, 
  LT_SHARED 
}; 
template&lt;LOCK_TYPE lckType&gt; 
struct LockTraits {}; 

template&lt;&gt; struct 
LockTraits&lt;LT_SHARED&gt; {}; 

template&lt;&gt; struct 
LockTraits&lt;LT_EXCLUSIVE&gt; {}; 
</pre>
<p>This is similar to the <tt class="literal">Int2Type</tt>
template explained in &quot;Modern C++ Design&quot; by Andrei Alexandrescu.
We essentially convert an enum into a type. Converting enums to
types helps the C++ compiler track bugs for you. This is immensely
helpful as you shall soon see.</p>
<p>Next, separate all the methods of the shared class into const
and non- const methods.</p>
<p>Whenever, a client code asks about SHARED access, give a const
reference to the shared object.</p>
<p>Only when it requests an EXCLUSIVE access, then only give out
non- const reference, essentially allowing client code to call any
method.</p>
<p>A singleton object of type <tt class="literal">CGetResource</tt>
grants these accesses.</p>
<pre class="programlisting">
class CDimension_I { 
  public: 
    virtual Id GetId() const = 0; // note the const 
    virtual void setId(Id dimId); // note the absence of const 
    // other interface methods 
}; 

const CDimension_I* inspectDim = ...; 
CDimension_I* mutateDim = ...; 

inspectDim-&gt;GetId();  // ok 
inspectDim-&gt;setId(3); // compilation error, can't call a non-const method on a const object 
mutateDim-&gt;GetId();   // ok, a non-const can call a const method 
mutateDim-&gt;setId(3);  // ok 
</pre>
<p>For more in-depth treatment of this pattern, please see a very
neat article by Kevlin Henney in CUJ - &quot;C++ Experts Forum&quot; online
article &quot;From Mechanism to Method: Further Qualifications&quot;.</p>
<pre class="programlisting">
template&lt;class DimT, class LckType&gt; 
class CdimWrapper { 
  protected: 
    DimT* m_pDim; 
    CSessionBase* m_pSession; 
  public: 
    CDimWrapper(DimT* pDim, 
                CSessionBase* pSession, 
                LockTraits&lt;LT_SHARED&gt;) 
      : m_pDim(pDim), 
        m_pSession(pSession) { 
    // Pass the buck onto session class. 
    // This takes care of multiple locking 
    m_pSession-&gt;Lock( 
      dynamic_cast&lt;Resource_m*&gt;(pDim), 
      LockTraits&lt;LT_SHARED&gt;()); 
    } 
}; 

class CBaseDimShr 
  : public CDimWrapper&lt;const CBaseDimension, LockTraits&lt;LT_SHARED&gt; &gt; { 
  public: 
    CBaseDimShr(const CBaseDimension* pDim, 
                CSessionBase* pSession, 
                CMapShr* pMap, 
                LockTraits&lt;LT_SHARED&gt;) 
      : CDimWrapper&lt;const CBaseDimension, LockTraits&lt;LT_SHARED&gt; &gt;( 
          pDim, pSession, pMap, LockTraits&lt;LT_SHARED&gt;()) {
    } 
    const CBaseDimension* operator-&gt;() const { 
      return m_pDim; 
    } 
}; 

class PtrBaseDimShr { 
  const CBaseDimShr* m_pLwDim; // note the const 
  // private copy ctor and assignment op not shown 
  public: 
    PtrBaseDimShr(const CBaseDimShr* pLwDim) 
      : m_pLwDim(pLwDim) { 
    }
    bool operator!() { 
      return m_pLwDim == 0; 
    }
    operator const void*() const { 
      return m_pLwDim; 
    }
    const CBaseDimShr&amp; operator-&gt;() const { 
      return *m_pLwDim; 
    }
    ~PtrBaseDimShr() { 
      delete m_pLwDim; 
    } 
};

class CBaseDimEx 
  : public CDimWrapper&lt;CBaseDimension, LockTraits&lt;LT_EXCLUSIVE&gt; &gt; { 
  public: 
    CBaseDimEx(CBaseDimension* pDim, 
               CSessionBase* pSession, 
               CMapEx* pMap, 
               LockTraits&lt;LT_EXCLUSIVE&gt;) 
      : CDimWrapper&lt;CBaseDimension, LockTraits&lt;LT_EXCLUSIVE&gt; &gt;( 
          pDim, pSession, pMap, LockTraits&lt;LT_EXCLUSIVE&gt;()) { 
    }
    CBaseDimension* operator-&gt;() { 
      return m_pDim; 
    } 
}; 

class PtrBaseDimEx { 
  CBaseDimEx* m_pLwDim; 
  // private copy ctor and assignment op not shown 
  public: 
    PtrBaseDimEx(CBaseDimEx* pLwDim) 
      : m_pLwDim( pLwDim) { 
    }
    bool operator!() { 
      return m_pLwDim == 0; 
    }
    operator void*() { 
     return m_pLwDim; 
    }
    CBaseDimEx&amp; operator-&gt;() { 
      return *m_pLwDim; 
    }
    ~PtrBaseDimEx() { 
      delete m_pLwDim; 
    } 
}; 

class CGetResource { 
  // This class takes care of point 3 
  // (allow multiple SHARED locks or a single EXCLUSIVE) 
  const CBaseDimShr* GetBaseDim(LockTraits&lt;LT_SHARED&gt;, 
                                BaseDimHandle hDimHdl, 
                                CSessionBase *session_ptr); 
  CBaseDimEx* GetBaseDim(LockTraits&lt;LT_EXCLUSIVE&gt;, 
                         BaseDimHandle hDimHdl, 
                         CSessionBase *session_ptr); 
  ......... 
}; 
</pre>
<p>Now a client acquires the shared object as follows:</p>
<pre class="programlisting">
void ClientClass::getBaseDimName(CSessionBase *pSession, 
                                 CGetResource* pGetRes, 
                                 BaseDimHandle hDim ) { 
  // original code 
  // CBaseDimension* pDim = ..... 
  PtrBaseDimShr pDim = pGetRes-&gt;GetBaseDim( LockTraits&lt;LT_SHARED&gt;(), hDim, pSession); 
} 
</pre>
<p>When the above function exits (either with a return statement or
by throwing an exception), this scheme guarantees that all locks
are released. Also, all the locking mechanism is neatly hidden. The
programmer just has to know</p>
<p>1 He is trying to get a shared resource ( <tt class=
"literal">LockTraits&lt;&gt;</tt> ) and</p>
<p>2 The call might sleep</p>
<p>Now with all this in place, suppose somebody does the
following:</p>
<pre class="programlisting">
PtrBaseDimShr pDim = pGetRes-&gt;GetBaseDim( LockTraits&lt;LT_EXCLUSIVE&gt;(), hDim, pSession); 
</pre>
<p>As <tt class="literal">LockTraits&lt;LT_EXCLUSIVE&gt;</tt> is a
class (an empty class), there is no function that satisfies the
above line. The compiler will kick in an error.</p>
<p>Now, the programmer corrects the mistake and obtains a shared
pointer.</p>
<pre class="programlisting">
Id id = 4; 
pDim-&gt;setId(id); // this again will kick in a compiler error. 
</pre>
<p>Let us trace this call to see what is going on. Trying to
resolve the above call, as <tt class="literal">pDim</tt> is not a
plain pointer, the compiler applies the <tt class=
"literal">operator -&gt;</tt> found in class <tt class=
"literal">PtrBaseDimShr</tt>, which returns a const object of
&quot;<tt class="literal">CBaseDimShr</tt>&quot;. Reapplying the <tt class=
"literal">operator -&gt;</tt> again, which returns a pointer to
const object of type <tt class="literal">CBaseDimension*</tt>. So
in essence, the above <tt class="literal">setId()</tt> call is
invoked on a const object of type <tt class=
"literal">CBaseDimension</tt>. However, as this is a non-<tt class=
"literal">const</tt> method, the call fails to compile.</p>
<p>Similarly, tracing through an exclusive mode pointer, we can
indeed see that the above call goes through fine.</p>
<p>This design was grafted onto a legacy code, so we did many other
nice things so it all worked quite well. The only other thing that
needed to be changed was the declaration of the pointers.
(<tt class="literal">PtrBaseDimShr</tt> instead of <tt class=
"literal">CBaseDimension*</tt> etc.). As the code was quite huge,
nearly 20000 lines and still growing, we never needed to know the
logic so as to know where to place the lock calls etc. We just
mechanically replaced the above declarations (using nifty VIM
macros) and the work got reduced to just few keystrokes. The unit
testing of the locking scheme was done using a Perl script (which
is an altogether different story - will do it some other time).</p>
<p>One queer thing I notice again and again. After all the core
design was coded in place, it was just a mechanical/routine matter
to extend it. The system just developed and extended itself. I
remember a similar experience while developing a schema language
using Lex, Bison and C++. This way of things is indeed very
gratifying. We did complete our part well before 15 days of the
release deadline, leaving everybody happy and some more spare time
for myself to linux it away.</p>
</p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
