简体   繁体   中英

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);
  }
}

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 (eg 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 (ie 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 (eg 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!!!

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.

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.

I was looking for the same coming from c# background and stumble upon this question a few times.. I know it's many years after it has been asked but now with c++11 you can use std::lock_guard and the syntax became very similar to c#

where in c# you have

object syncObj;
...
lock(syncObj){ ... }

in c++11 you can use a mutex as a sync and lock_guard similarly to lock

std::mutex m;
...
std::lock_guard<std::mutex> lock(m);{...}

if you

#define lock(mutex) std::lock_guard<std::mutex> lock(mutex);

then it would really look the same :)

Here is everything you need : Implementing a lock keyword in C++

C++ doesn't have a lock keyword, but you can make one yourself. Given a Mutex class which has Lock() and Unlock() member functions (and perhaps an IsLocked() for convenience) most C++ programmers would immediately write an AutoLock, somewhat like this:

class AutoLock
{
public:
    AutoLock(Mutex& m): m_mutex(m)  { m_mutex.Lock(); }
    ~AutoLock()                     { m_mutex.Unlock(); }
    operator bool()                 { return m_mutex.IsLocked(); }
private:
    Mutex&   m_mutex;
};

Normal use of this thing would look like this:

{
    AutoLock lock(m_mutex);
    // my protected code here
}

But with a simple preprocessor trick you can make the syntax identical to C#:

#define lock(x) if (!(AutoLock _l = x)); else

C++ doesn't have a lock keyword. You could use a mutex .

你不能,不存在这样的关键词,你得到的最接近的东西是boost的范围锁 (它可以使用boost mutex)。

I would use the Boost synchronization library . If you can't for some reason, I'd hack something up like this:

class CriticalSection {
    CRITICAL_SECTION m_cs;

public:
    CriticalSection() {
        ::InitializeCriticalSection(&m_cs);
    }

    ~CriticalSection() {
        ::DeleteCriticalSection(&m_cs);
    }

    void Lock() {
        ::EnterCriticalSection(&m_cs);
    }

    void Unlock() {
        ::LeaveCriticalSection(&m_cs);
    }
};

class CriticalSectionLocker {
    CriticalSection& m_cs;
    bool m_bLocked;
public:
    CriticalSectionLocker(CriticalSection& cs, bool bLockNow = true) : m_cs(cs), m_bLocked(bLockNow) {
        if(bLockNow)
            m_cs.Lock();
    }

    ~CriticalSectionLocker() {
        if(m_bLocked)
            m_cs.Unlock();
    }

    void Lock() {
        m_cs.Lock();
        m_bLocked = true;
    }

    void Unlock() {
        m_cs.Unlock();
        m_bLocked = false;
    }
};

Caveat Emptor: This code hasn't passed through a compiler. YMMV.

This code allows you to do stuff like this:

class SomeClass {
    CriticalSection m_cs;
    SomeResource m_resource;

public:
    void SomeOperation() {
        CriticalSectionLocker lock(m_cs);
        m_resource.DoSomething();
    }
};

The lock is locked in the scope of SomeClass::SomeOperation() . You can also release the lock by calling its Unlock() method, should you no longer need to hold the lock.

This code is by no means generalized. It can be tidied up with template-awesomeness, and make it general enough to make use of mutexes, and other operating system objects. But if want to go there, I'd recommend using the boost libraries instead.

You can use std::lock_guard

Here's the simplified example from that documentation:

std::mutex resource_mutex;
...
{
    std::lock_guard<std::mutex> lock(resource_mutex); // The variable name ("lock") doesn't matter since it is not supposed to be used anywhere else.
    ...
    // safe to use resource here
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM