Is this a valid way to Implement locks under CLR in unmanaged code?

38 Views Asked by At

Just a heads up if you planning to look into this question you are probably going to have to download the 7-zip SDK its got far too many macro definitions for me to copy and paste them all here.

Disclaimer:

All of this code is from the 7zip SDK and I take no ownership of it.

First some background: I am implementing a CLR API to the 7-zip SDK that calls the methods directly, no use of COM. I have successfully done this before at a prior workplace and am using my time unemployed to create a more extensive library.

The API is broken into 2 layers. An unmanaged API that can be called from C++ which can then be called using CLR from C#. So two APIs.

Why? Well if we were going to use the 7-zip SDK my boss mandated that we don't use COM.

The issue:

I find myself needing to have lock functionality. However I cannot use std::mutex or any other standard std option due to the /clr flag.. I also cannot used the <msclr/lock.> solution due to this error: C3076 you cannot embed an instance of a reference type, 'msclr::lock', in a native type.

This is all expected. However the creator(s) of the 7-zip SDK have their own solution given that the SDK can be successfully compiled using the /clr flag (it does take a bit more work than that but I won't go into that here).

7-zip SDK creates its own lock. The code can be found here: SDK Download: https://7-zip.org/sdk.html Source source path within SDK: "sdk\lzma2201\CPP\Windows\Synchronization.h" & "sdk\lzma2201\CPP\Windows\Synchronization.cpp"

My Question:

Nothing special. Is this a valid solution to the problem?

I went ahead and used it in production code (with manager's approval of course) for the SDK (but nowhere else) however it appears to be too useful not to use if it indeed is a safe and valid solution. I am only an intermediate C++ developer at best so my knowledge of all the minefields you can cross to write good C++ code is limited.

Testing never revealed an issue and I did try to force an issue with multithreading.

The code:

Here is what I think is the most relevant code for this solution but as I said a dive into the 7-zip SDK will probably be required.

From "sdk\lzma2201\CPP\Windows\Synchronization.h"

class CCriticalSection  MY_UNCOPYABLE
{
  ::CCriticalSection _object;
public:
  CCriticalSection() { CriticalSection_Init(&_object); }
  ~CCriticalSection() { CriticalSection_Delete(&_object); }
  void Enter() { CriticalSection_Enter(&_object); }
  void Leave() { CriticalSection_Leave(&_object); }
};

class CCriticalSectionLock  MY_UNCOPYABLE
{
  CCriticalSection *_object;
  void Unlock()  { _object->Leave(); }
public:
  CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); }
  ~CCriticalSectionLock() { Unlock(); }
};

From "sdk\lzma2201\CPP\Common\MyTypes.h"

#define CLASS_NO_COPY(cls) \
  private: \
  cls(const cls &); \
  cls &operator=(const cls &);

class CUncopyable
{
protected:
  CUncopyable() {} // allow constructor
  // ~CUncopyable() {}
CLASS_NO_COPY(CUncopyable)
};

#define MY_UNCOPYABLE  :private CUncopyable
// #define MY_UNCOPYABLE

From "sdk\lzma2201\C\Threads.h"

typedef CRITICAL_SECTION CCriticalSection;
WRes CriticalSection_Init(CCriticalSection *p);
#define CriticalSection_Delete(p) DeleteCriticalSection(p)
#define CriticalSection_Enter(p) EnterCriticalSection(p)
#define CriticalSection_Leave(p) LeaveCriticalSection(p)

And so an example of usage: From "sdk\lzma2201\CPP\UI\Console\ExtractCallbackConsole.cpp"

#ifndef _7ZIP_ST
static NSynchronization::CCriticalSection g_CriticalSection;
#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
#else
#define MT_LOCK
#endif

And later in the same file its used thusly:

STDMETHODIMP CExtractCallbackConsole::SetTotal(UInt64 size)
{
  MT_LOCK

  if (NeedPercents())
  {
    _percent.Total = size;
    _percent.Print();
  }
  return CheckBreak2();
}

If you think I am missing a part or that posting more of the code would help feel free to let me know.

Summary: So I could just use it and then go on but once you strip away all the layers the macros the solution seems so... well... simple. Its almost too good to be true but I am not qualified to make that determination. Is it?

So is this safe to use under the conditions where you have /clr enabled but cannot use <msclr/lock.h>? Or are their some hidden pitfalls? Any help in understanding would be appreciated.

0

There are 0 best solutions below