🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.nativeapi
6 messages
6 total messages Started by static array? Tue, 19 Jun 2007 15:20
bizarre behaviour of a mutex handler class and std::auto_ptr
#1783
Author: static array?
Date: Tue, 19 Jun 2007 15:20
65 lines
2765 bytes
I require a global mutex for my application to sync resources across 
different instances of the app, even running in different user sessions.

I created a class to manage this for me, all I have to do is create an 
instance to aquire the mutex and detroy it to release it.

int GlobalMutexReferenceCount = 0;
__fastcall TLicenseMutexHandler::TLicenseMutexHandler(const AnsiString 
LicenseProjectName)
{

  SetMutexName(LicenseProjectName);

  if (++GlobalMutexReferenceCount > 1)
    return;

  FMutexHandle = CreateMutex(NULL, false, FMutexName.c_str());
  WaitForSingleObject(FMutexHandle, INFINITE);
}

__fastcall TLicenseMutexHandler::~TLicenseMutexHandler()
{
  if (--GlobalMutexReferenceCount > 0)
    return;

  ReleaseMutex(FMutexHandle);
  CloseHandle(FMutexHandle);
}

void __fastcall TLicenseMutexHandler::SetMutexName(const AnsiString 
ALicenseProjectName)
{
  FMutexName = "Global\\" + AnsiReplaceText(ALicenseProjectName, "\\", "_");
}

Looks good - OK - so now an example. In the scope of a function that 
accesses the protected resource I have:

void __fastcall Func()
{
  std::auto_ptr<TLicenseMutexHandler>pLMH(new 
TLicenseMutexHandler(MainLFName));
  // do stuff to resource
}

** When the function exits, I can see the object gets destroyed correctly 
and themutex gets released and closed. However, immediately upon the return 
(after the destruction), I get an access violation in the kernel:
First chance exception at 0x7C812A5B. Exception class EAccessViolation with 
message 'Access violation at address 00000000...

** Now - here is the BIZARRE part: All I do is change the code to be:

void __fastcall Func()
{
  TLicenseMutexHandler * pLMH = new TLicenseMutexHandler(MainLFName);
  // do stuff to resource
  delete  pLMH;
}

And the AV goes away!

Any ideas why?

TIA
more info from OP
#1785
Author: static array?
Date: Tue, 19 Jun 2007 15:38
36 lines
2145 bytes
OK - so I found that just by wrapping my auto_ptr in an internal block 
inside the function, that the AV also goes away.

** This leads me to believe there is some sort of issue with unwinding the 
stack and destruction of the auto_ptr.

The problem function more closely looks like this:

//-- this version works fine
long __fastcall TObj::Func(AnsiString a,
                                          AnsiString b,
                                          AnsiString c,
                                          int d,
                                          long e /*= 0*/)
{
  try{
   std::auto_ptr<TLicenseMutexHandler>pLMH(new TLicenseMutexHandler(a));
    // do stuff to protected resource
  }__finally {  }
  return 0;
}



//-- this version crashes in the kernel - AV!
long __fastcall TObj::Func(AnsiString a,
                                          AnsiString b,
                                          AnsiString c,
                                          int d,
                                          long e /*= 0*/)
{
  std::auto_ptr<TLicenseMutexHandler>pLMH(new 
TLicenseMutexHandler(MainLFName));
  // do stuff to protected resource
  return 0;
}
Re: more info from OP
#1786
Author: Dennis Jones
Date: Tue, 19 Jun 2007 16:11
11 lines
1245 bytes
"static array?" <nospam@nospam.com> wrote in message 
news:4677f899$1@newsgroups.borland.com...
> OK - so I found that just by wrapping my auto_ptr in an internal block 
> inside the function, that the AV also goes away.

Hmm...sounds like a bug.  Which compiler are you using?

Have you tried using boost::scoped_ptr<> instead of std::auto_ptr<>?

- Dennis 
Re: more info from OP
#1787
Author: static array?
Date: Tue, 19 Jun 2007 16:52
23 lines
1639 bytes
BCB6 patched.

No I havent tried the Boost libs.  Is it easy/free to install and use from 
BCB6?

TIA.



"Dennis Jones" <nospam@nospam.com> wrote in message 
news:4678003e$1@newsgroups.borland.com...
>
> "static array?" <nospam@nospam.com> wrote in message 
> news:4677f899$1@newsgroups.borland.com...
>> OK - so I found that just by wrapping my auto_ptr in an internal block 
>> inside the function, that the AV also goes away.
>
> Hmm...sounds like a bug.  Which compiler are you using?
>
> Have you tried using boost::scoped_ptr<> instead of std::auto_ptr<>?
>
> - Dennis
> 
Re: more info from OP
#1788
Author: Dennis Jones
Date: Tue, 19 Jun 2007 17:14
20 lines
1709 bytes
"static array?" <nospam@nospam.com> wrote in message 
news:46780a16$1@newsgroups.borland.com...
> BCB6 patched.
>
> No I havent tried the Boost libs.  Is it easy/free to install and use from 
> BCB6?

Yes, Boost is free.  And depending on what you want from Boost, it *can* be 
easy.  In your case, all you care about is smart pointers, which are defined 
in header files, so building the Boost libraries is not necessary.

For BCB6/BDS2006, use Boost 1.33.1 (not 1.34.0).  http://tinyurl.com/ywamx3

If you eventually decide to use other Boost libraries (besides smart 
pointers), you might also want to get bcbboost because it corrects a few 
issues in various Boost libraries' compatibility with BCB. 
http://tinyurl.com/33v6al

- Dennis 
Re: bizarre behaviour of a mutex handler class and std::auto_ptr
#1789
Author: Remy Lebeau (TeamB)
Date: Tue, 19 Jun 2007 17:42
179 lines
5792 bytes
"static array?" <nospam@nospam.com> wrote in message
news:4677f486@newsgroups.borland.com...

> I created a class to manage this for me, all I have to do is
> create an instance to aquire the mutex and detroy it to release it.

You are not doing that correctly.

>   if (++GlobalMutexReferenceCount > 1)
>     return;

Only when your class has 1 active instance is the mutex actually
created and obtained.  Any additional instances beyond that in the
same process do not access the mutex at all.

>   FMutexName = "Global\\" + AnsiReplaceText(ALicenseProjectName,
"\\", "_");

The "Global" prefix only works on XP and higher, or Win2000 with
Terminal Services.  Any OS that is older than that will fail to create
the mutex  as "\\" is an illegal character in those versions.  So you
should be checking the OS version in order to decide whether to apply
that prefix or not.

> Looks good - OK - so now an example. In the scope of a function
> that accesses the protected resource I have:

You don't need the auto_ptr at all.  Your class is not derived from
TObject, so there is nothing preventing you from creating the class
directly on the stack.

Try this instead:

    int GlobalMutexReferenceCount = 0;

    __fastcall TLicenseMutexHandler::TLicenseMutexHandler(const
AnsiString &LicenseProjectName)
    {
        if( GlobalMutexReferenceCount == 0 )
            FMutexHandle = CreateMutex(NULL, FALSE,
GetMutexName(LicenseProjectName).c_str());

        ++GlobalMutexReferenceCount;

        if( FMutexHandle )
            WaitForSingleObject(FMutexHandle, INFINITE);
    }

    __fastcall TLicenseMutexHandler::~TLicenseMutexHandler()
    {
        --GlobalMutexReferenceCount;
        if( FMutexHandle )
        {
            ReleaseMutex(FMutexHandle);
            if( GlobalMutexReferenceCount == 0 )
                CloseHandle(FMutexHandle);
        }
    }

    AnsiString __fastcall TLicenseMutexHandler::GetMutexName(const
AnsiString &ALicenseProjectName)
    {
        AnsiString Prefix;
        if( (Win32MajorVersion > 5) || ((Win32MajorVersion == 5) &&
(Win32MinorVersion >= 1)) )
            Prefix = "Global\\";
        return Prefix + AnsiReplaceText(ALicenseProjectName, "\\",
"_");
    }

    void __fastcall Func()
    {
        TLicenseMutexHandler LMH(MainLFName);
        // do stuff to resource
    }


With that said, it is not very efficient to pass the mutex name around
on every instance, especially since most of them will never use it.
If you really want to go this class approach, then you should wrap the
actual mutex in one class that you create only once, and then use
another class to lock/unlock it when needed.  For example (untested):

    class TLicenseMutex
    {
        friend class TLicenseMutex::Lock;

    private:
        HANDLE hMutex;

    public:
        TLicenseMutex(const AnsiString &ProjectName);
        ~TLicenseMutex();

        class Lock
        {
        private:
            TLicenseMutex &refMutex;
            bool bLocked;

        public:
            Lock(TLicenseMutex &Mutex, DWORD Interval = INFINITE);
            ~Lock();

            operator bool () const;
            bool operator ! () const;
        };
    };


    TLicenseMutex::TLicenseMutex(const AnsiString &LicenseProjectName)
        : hMutex(NULL)
    {
        AnsiString Prefix;

        if( (Win32MajorVersion > 5) || ((Win32MajorVersion == 5) &&
(Win32MinorVersion >= 1)) )
            Prefix = "Global\\";

        hMutex = CreateMutex(NULL, FALSE, (Prefix +
AnsiReplaceText(ALicenseProjectName, "\\", "_")).c_str());
    }

    TLicenseMutex::~TLicenseMutex()
    {
        if( hMutex )
            CloseHandle(hMutex);
    }


    TLicenseMutex::Lock::Lock(TLicenseMutex &Mutex, DWORD Interval)
        : refMutex(Mutex), bLocked(false)
    {
        bLocked = (WaitForSingleObject(refMutex.hMutex, Interval) ==
WAIT_OBJECT_0);
    }

    TLicenseMutex::Lock::~Lock()
    {
        if( bLocked )
            ReleaseMutex(refMutex.hMutex);
    }

    TLicenseMutex::Lock::operator bool () const
    {
        return bLocked;
    }

    bool TLicenseMutex::Lock::operator ! () const
    {
        return !bLocked;
    }


Then you can do the following:

    // globally created, or a member of the MainForm, or whatever...
    TLicenseMutex MainMutex(MainLFName);

    void __fastcall Func()
    {
        TLicenseMutex::Lock lock(MainMutex);
        if( lock )
        {
            // do stuff to resource
        }
    }

    void __fastcall Func2()
    {
        TLicenseMutex::Lock lock(MainMutex);
        if( !lock )
            return;
        // do stuff to resource
    }


Gambit
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads