• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 947
  • Last Modified:

CreateSemaphore does not return "ERROR_ALREADY_EXISTS"

I am creating a semaphore in a program and checking for GetLastError set to ERROR_ALREADY_EXISTS. It does not return this on a second instance of the program. Why?

e.g.

in C++

     HANDLE hSemaphore = CreateSemaphore( NULL, 1, 1, "MySemaphore" );
     if ( GetLastError() == ERROR_ALREADY_EXISTS )
     {
          // Display a message to the user and exit
     }
     else
     {
          // Run the program
     }
    ReleaseSemaphore(hSemaphore,1,NULL);
     CloseHandle(hSemaphore );

It does not return ERROR_ALREADY_EXISTS on the second instance of the program. If I add a messagbox in the "run the program" then the first instance pops that messsagebox and the second does get a return of ERROR_ALREADY_EXISTS and pops it's messagenox to tell me so. I don't see why this happens.

Same thing HAPPENS  VB with a waitable timer:

 Private Sub Form_Load()
   Dim res&
   Dim ft As FILETIME
 
   TimerObjectHandle = CreateWaitableTimer(0, True, "MyTimer")
   If Err.LastDllError = ERROR_ALREADY_EXISTS Then
      ' Another app already created the timer,
      ' we may need to go to sleep now
     MsgBox "crWT already exists", vbOKOnly + vbMsgBoxSetForeground, "mdo"
   Else
     ' MsgBox "crWT did not exist", vbOKOnly + vbMsgBoxSetForeground, "mdo"
      'do something
   End If
   Call CloseHandle(TimerObjectHandle)
   End
End Sub

If I run this as is above twice at the same time no message pops up. If I remove the comment on the second message box then both mesage boxes pop up. So what gives, why does this happen?

Thanks for assistance, I need this resolved asap.
Mike
0
flmike1
Asked:
flmike1
1 Solution
 
krbatgeCommented:
I'd say that when you run it twice (without the messagebox in 'Run the program') the first instance finsihes so quickly that the Semaphore is released and the second instance can create it successfully.

When you add the messagebox, the first instance is still running and holding the semaphore (becuase the messagebox is displayed), so when the second instance tries to create it it fails as expected.
0
 
DanRollinsCommented:
Agreed.  If the first program closes the semaphore prematurely, then the second program will see nothing wrong with running.   Incidently, the normal way to test for failure is:

    HANDLE hSem = CreateSemaphore( NULL, 1, 1, "MySemaphore" );
    if (hSem != NULL && GetLastError() == ERROR_ALREADY_EXISTS)  {
          ...msg that the semaphore exists...;
     }

The reason you should check the value of hSem -- and not just GetLastError() -- is that some other error may occur (such as something related to SECURITY_ATTRIBUTES).

Be sure to see:
    How to limit 32-bit applications to one instance in Visual C++
    http://support.microsoft.com/kb/q243953/
That clever object does it all... just instantiate it as a global in your main module and when it destructs it goes away so that another instance of the program (or any program that uses the same string as the name of the mutex) will then be able to run.

As to the VB dillybob, see:
     How To Use SetWaitableTimer With Visual Basic
     http://support.microsoft.com/kb/q231298/    

-- Dan
0
 
flmike1Author Commented:
Ordinarily I would agree. However immediately after the CreateSemaphore the program actually does a WaitforSIngleObject on the semaphore handle to grab the only 1 count avialable then it does a bunch of things: Starts a new process with CreateProcess to start IEXPLORE.exe with a URL it builds. Since the URL itself causes a lot of things to happen my process program then  creates an waitable timer and and waits on it for 10 seconds to allow the browser to complete a lot of intialization stuff it does including interacting with the web server. When the timer is signaled my process then releases the semaphore for any second or more instances so they can repeat this. So since my first instance is waitng for 10 seconds the second instance should fire up (I assume) do it's CreateSemahpore and should get ERROR_ALREADY_EXISTS since the first instance hasn't released it yet since it's waiting on the timer. So, I don't get what I'm missing here. The second instance is held when it waits for the the semaphore but I am trying to avoid having the second and subsequent instances do the 10 second timer wait as they really don't need to. After the first instances' created browser process is done with initialization everything the second and more need is already loaded (e.g. a COM server that only needs to be loaded once).  

Mike
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
DanRollinsCommented:
I can't visualize exactly what you are going for... is your user running multiple copies of your program, each accessing a different IExplorer.Exe?  Is your program running multiple threads each accessing the same (or different?) IExplorer.Exe?

If you are accessing an external IE window, you might consider instead using a WebBrowser control.  Except in unusual situations, it will give you the same capabilities and it provides feedback on every operation -- such as after you do a Navigate() fn, you will get a call to your OnDocumentComplete() handler.

-=-==-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=
In any case, I'm worried about that arbitrary 10-second delay -- Isn't there some way to get notified when the initialization is complete (rather than using the WaitableTimer) ?  Won't everything crumble like a house of cards if the initialization takes 11 seconds or 20 seconds?

I also think that you may be complicating things unnecessarily.  In general, these things are pretty simple -- You need a flag to tell each process (or thread) to go ahead or wait.  If you don't want the process to wait, just don't set the flag :-)

-- Dan
0
 
mahesh1402Commented:
If any other calls are made on your thread between the time you call CreateSemaphore() and when you call GetLastError(), the GetLastError() value is going to be unreliable.  

Put another way, the call to GetLastError() should be placed immediately after the API call you are checking -- and then only if the API call return code indicates that the last error value will be valid.


-MAHESH
0
 
mxjijoCommented:

Two things can cause this.

1) As you guys been discussing premature close of semaphore.
    To test this make a DuplicateHandle() to make sure the semaphore lives.
    Something like this..

     HANDLE hSemaphore = CreateSemaphore( NULL, 1, 1, "MySemaphore" );
     if ( GetLastError() == ERROR_ALREADY_EXISTS )
     {
          // Display a message to the user and exit
     }
     else
     {
          HANDLE duplicateHandle = NULL; // local variable just for testing.... will cause handle leak.
          DuplicateHandle(GetCurrentProcess(), hSemaphore, GetCurrentProcess(), &duplicateHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
          // Run the program
     }


2) Namespace issue - may be this is not your case.. still..
    If you are running terminal server, windows do care about namespace.
    All objets created from services will be in global namespace by default.
    This means you can have two knl objects with the same name, one under global name sp and one under local name space

0
 
flmike1Author Commented:
To krbatge,  DanRollins, mahesh1402, and mxjijo
Thanks to you for the suggestions. I was finally able to resolve the problem on my own. I went back to the module that invoked my application that was having the semaphore problem. As I suggested it would invoke my module multiple times based on it's own input drivers. It turns out the invoking app was using a WinExec API call to start my app and this caused the problem. From the help documentation I found that WinExec does not return unitl that invoked app issues a GetMessage or until the invoked app terminates. As it happens my invoked app does not issue any GetMessage since it does not need to, there are no dialog windows. So in fact when my app was invoked a second or more times, each would only be run once the previous one had completed. As a result it would be correct to not return the ERROR_ALEADY_EXISTS return when creating the semaphore as the  I changed the calling app to use CreateProcess instead of WinExec and that cleared up the problem. NOt I do get the ERROR_ALREADY_EXISTS as I expected I should, i.e. my code was correct all along. Thanks again.
0
 
DanRollinsCommented:
Since you solved this yourself (and the solution is useful), please request closure of the question as described here: http://www.experts-exchange.com/help.jsp#hi70  Thanks!
0
 
GranModCommented:
Closed, 300 points refunded.
GranMod
The Experts Exchange
Community Support Moderator of all Ages
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Tackle projects and never again get stuck behind a technical roadblock.
Join Now