views:

49

answers:

3

I'm looking for a way with no side effects.

Ideally, the following code would do the trick:

long currentCount = 0;  
::ReleaseSemaphore(h, 0, &currentCount);  

But unfortunately 0 is not allowed as the value of lReleaseCount, so the call returns FALSE.

A: 

There is no such thing as a "current count" of a Win32 semaphore - which is why you can't get it.

I mean, patently, at some point of time the count on a semaphore will be some value, but from the point of view of a thread, unless it takes action to increase or decrease the semaphore count, another thread might make any answer retrieved entirely invalid the moment it is computed.

It is for this reason that windows api synchronization functions do not let you take the previous lock count without a side effect. The side effect guarantees that you have a valid window of opportunity to actually use the value in a meaningful way.


The obvious "work around" would be to do something like

LONG count = 0;
if( WAIT_OBJECT_0 == WaitForSingleObject(hSemaphore,0L))
{
  // Semaphores count is at least one.
  ReleaseSemaphore(hSemaphore,1,&count);
}

Why is this better? I'm not sure. But perhaps there is a possibility of doing something meaningful between waiting and releasing that would have been a race condition if ReleaseSemaphore was allowed to release 0.

Chris Becke
Such ability is useful for external monitoring (an example would be a producer and consumer(s), where the semaphore's count represents the number of objects still pending). Therefore I'm surprised that it is undoable.
Paul Oyster
The problem with the workaround is that it will likely skew your actual use of the semaphore; you'll potentially introduce waits into the threads that are using the semaphore for the intended purpose. The waits introduced will be small but probably enough to cause context switching. Better to just maintain your own monitoring counter.
Len Holgate
+1  A: 

If you want that value for external monitoring (as you suggest in your comment) then either use the previous value after a call to ReleaseSemaphore() or IMHO a better solution is that you implement your own 'interlocked' counter in addition to your semaphore; you then have your monitoring count and can access it in any way you like... Just don't use it as a way of seeing if you can 'enter' the semaphore...

As Chris rightly says, you can't obtain the current count as it is potentially always changing.

Len Holgate
A: 

The sysinternals tool Process Explorer can display the internals of win32 handles, including semaphores and their current/max counts. Good enough for debugging but not so useful for automated monitoring.

If Process Explorer can do it, you probably can too ... but it will probably require deep knowledge of windows internals.

Paul Du Bois