Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conversion of lock keyword of C# to C++

How can I implement lock keyword of C# in C++? The code in c# is as follows:

try
{
  lock (matrixLock)
  {
    ThisTransformation.get_Renamed(matrix);
  }
}
like image 996
Ravinder Singh Avatar asked Jan 03 '11 16:01

Ravinder Singh


3 Answers

A. - Fast Answer

Assuming you have a Mutex and a Lock object (your mileage may vary):

#define MY_OWN_LOCK(mm_mutex)                                         \
                                                                      \
    if(bool b_1227F2B8_136B_11E1_973D_7D0B4924019B = false)           \
        ;                                                             \
    else                                                              \
        for(Lock lock_1227F2B8_136B_11E1_973D_7D0B4924019B(mm_mutex); \
            !b_1227F2B8_136B_11E1_973D_7D0B4924019B;                  \
            b_1227F2B8_136B_11E1_973D_7D0B4924019B = true)

Which can be used as:

Mutex mutex ;

void foo()
{
    // not locked

    MY_OWN_LOCK(mutex)
    {
       // locked
    }

    // not locked
}

B. - Detailed Answer

It depends on the library you'll be using.

B.1 - Pre-requisites

Let's assume you have:

  • a Mutex object, which have a lock() and an unlock() methods
  • a Lock object, which have a constructor with a Mutex as parameter, and calls its lock() method at construction, and unlock() method at destruction

So, you have something like:

class Mutex
{
    public :
        lock() ;
        unlock() ;
        // etc.
} ;

class Lock
{
    Mutex & m_mutex ;
    public :
        Lock(Mutex & p_mutex) : m_mutex(p_mutex)
            { this->m_mutex.lock() ; }
        ~Lock()
            { this->m_mutex.unlock() ; }
        // etc.
} ;

B.2 - Raw C+ use

If you are unfamiliar with C++'s RAII, your code will be like:

void foo()
{
   // not locked
   mutex.lock() ;
   // locked !
   mutex.unlock() ;
   // not locked
}

This code is so wrong I won't ever discuss it (Google "exception safety" if needed).

B.3 - Raw C++ use

void foo()
{
   // not locked
   {
      Lock lock(mutex) ;
      // locked !
   }
   // not locked
}

B.4 - Macro-enhanced C++ use

With the following macro:

#define LOCK(mm_mutex)                                     \
                                                           \
                 if(bool b = false)                        \
                    ;                                      \
                 else                                      \
                    for(Lock lock(mm_mutex); !b; b = true)

You'll be able to write:

void foo()
{
   // not locked

   LOCK(mutex)
   {
      // locked !
   }

   // not locked
}

B.5 - Why so complicated ?

Most lock macros rely on the lock object to be testable. This either needs an implementation of the Safe Bool Idiom (which is overkill for the current use), or the need for the lock object to be castable to bool, which brings its own (large) set of flaws to the class.

In the current implementation, the if is used to declared the boolean that will control the for's body execution, while the for itself is used to declare the Lock object itself.

I believe this pattern is called something like "C++ variable injection".

B.6 - Performance ?

Note that you're locking something, so the code inside the mutex.lock() and mutex.unlock() will take a lot more cycles than anything in the macro.

In non-optimized builds, the if and for jumps will show (e.g. try it step-by-step on a visual debugger), but in optimized build, the whole if and for will be optimized away (there's no difference between the assembly generated by the "raw C++ use" and the "macro-enhanced C++ use".

B.7 - Caution !!!

The macro above is simplified for educational purposes. To use it on production code, you must:

  • "namespace" the macro name (i.e. prefix it with some kind of unique name, as the BOOST_ part of the BOOST_FOREACH macro)
  • make the boolean b and the Lock lock variable "unique" to make sure they won't collide with user code. I usually use a GUID/UUID suffix for that (e.g. b_ABCD_ABCD_AB_ABCDEF and lock_ABCD_ABCD_AB_ABCDEF)

B.8 - Sources

I first saw that pattern in an article (I believe by Andrei Alexandrescu), and indeed, I was searching for it when I stumbled on this SO question.

:-)

As soon as I find the source, I'll update this answer with the correct link.

Edit: Found the source!!!

  • FOR_EACH and LOCK, by Eric Niebler and Anson Tsao : http://drdobbs.com/184401723 (or the printable version http://drdobbs.com/article/printableArticle.jhtml?articleId=184401723, better formatted IMHO)
  • Safe Bool Idiom, by Bjorn Karlsson : http://www.artima.com/cppsource/safebool.html
like image 50
paercebal Avatar answered Nov 14 '22 09:11

paercebal


You can use boost::mutex and boost::scoped_lock for this:

boost::mutex matrix_mutex;

// ...
try {
    boost::scoped_lock lock(matrix_mutex);
    // ... everything in this scope is now locked
} // ....

You can use macros and for-loops to give you a lock keyword, although I would strongly advise against doing so, since that will break code that happens to use lock as an identifier.

like image 44
Michael Aaron Safyan Avatar answered Nov 14 '22 08:11

Michael Aaron Safyan


The C# lock keyword is not a mutex. Instead, it calls Monitor::Enter() Try this. Also look at MSDN reference.

  // Request the lock, and block until it is obtained.
  Monitor::Enter(m_inputQueue);
  try
  {
     // Write your code here.
  }
  finally
  {
     // Ensure that the lock is released.
     Monitor::Exit(m_inputQueue);
  }

Note: this answer assumes you are targeting C++ CLI.

like image 3
Matt Brunell Avatar answered Nov 14 '22 10:11

Matt Brunell