Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CreateMeteredSection slot?

3 views
Skip to first unread message

Bruce Chastain

unread,
Feb 24, 2005, 3:18:06 PM2/24/05
to
I'm trying to replace a Mutex semaphore (used to protect a memory resident
database) with something faster (and hopefully as simple to use), and
Metered Sections have been suggested.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_metrsect.asp

but I'm having trouble understanding the description of how to properly use
it.

CreateMeteredSection() requires two parameters that I'm hoping someone can
explain them to me, lInitialCount and lMaximumCount. The descriptions refer
to "slots" but it doesn't explain what a "slot" is or how many slots I want.

Remember that my purpose is to replace a system (cross process) mutex
semphore.

Thanks for any pointers.

Bruce.


Jim

unread,
Feb 24, 2005, 3:37:34 PM2/24/05
to
The SDK CreateSemaphore() explains lInitialCount, lMaximumCount -- typically
set to 0 on initialization to indicate nothing-yet-to-do.

The "slot" is just the whatever-resource-you-are-counting. If just
mutual-exclusion is needed and no counting, then the max lMaximumCount could
be 1.

If you don't need counting, this is doing extra work and may not be faster
than a mutex.


"Bruce Chastain" <bcha...@XNOSPAMXhyperfeed.com> wrote in message
news:eJGW22qG...@TK2MSFTNGP12.phx.gbl...

Marc Sherman

unread,
Feb 24, 2005, 3:40:35 PM2/24/05
to
Bruce Chastain wrote:
> I'm trying to replace a Mutex semaphore

"Mutex semaphore"? I don't believe there is such a thing in Win32.
You're either using a mutex or a semaphore. The former is created with
CreateMutex() and the later with CreateSemaphore().

>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_metrsect.asp


> CreateMeteredSection() requires two parameters that I'm hoping
someone can
> explain them to me, lInitialCount and lMaximumCount. The
descriptions refer
> to "slots" but it doesn't explain what a "slot" is or how many slots
I want.

>From skimming the link you provided, it sounds like they are equivalent
to the same parameters as in the call to CreateSemaphore().

Marc

Bruce Chastain

unread,
Feb 24, 2005, 3:52:48 PM2/24/05
to
"Marc Sherman" <mshe...@go-eol.com> wrote in message
news:1109277635....@l41g2000cwc.googlegroups.com...

> "Mutex semaphore"? I don't believe there is such a thing in Win32.
> You're either using a mutex or a semaphore. The former is created with
> CreateMutex() and the later with CreateSemaphore().

Sorry for my description. I've read of a mutex being described as being as
a type of semphores.

I'm currently using a mutex to protect shared memory, but it's eating way
too much in performance.

Bruce.


Bruce Chastain

unread,
Feb 24, 2005, 3:57:30 PM2/24/05
to
"Jim" <jam...@hotmait.con> wrote in message
news:OfHdQDrG...@TK2MSFTNGP10.phx.gbl...

> The SDK CreateSemaphore() explains lInitialCount, lMaximumCount --
> typically
> set to 0 on initialization to indicate nothing-yet-to-do.

Thanks. That helps.

> The "slot" is just the whatever-resource-you-are-counting. If just
> mutual-exclusion is needed and no counting, then the max lMaximumCount
> could
> be 1.
> If you don't need counting, this is doing extra work and may not be faster
> than a mutex.

I do not need resource counting. Just the simplest functional equivalent of
a cross-process Critical Section.

Bruce.


Marc Sherman

unread,
Feb 24, 2005, 4:19:51 PM2/24/05
to
Bruce Chastain wrote:
> "Marc Sherman" <mshe...@go-eol.com> wrote in message
> news:1109277635....@l41g2000cwc.googlegroups.com...
> > "Mutex semaphore"? I don't believe there is such a thing in Win32.
> > You're either using a mutex or a semaphore. The former is created
with
> > CreateMutex() and the later with CreateSemaphore().
>
> Sorry for my description. I've read of a mutex being described as
being as
> a type of semphores.

Oh okay. Anyway, read about the lInitialCount and lMaximunCount
parameters in the docs for CreateSemaphore(). My guess is this would
also apply to the parameters of the same name for creating a metered
section.

Marc

Bruce Chastain

unread,
Feb 24, 2005, 4:24:49 PM2/24/05
to
"Marc Sherman" <mshe...@go-eol.com> wrote in message
news:1109279991.0...@f14g2000cwb.googlegroups.com...

> Oh okay. Anyway, read about the lInitialCount and lMaximunCount
> parameters in the docs for CreateSemaphore(). My guess is this would
> also apply to the parameters of the same name for creating a metered
> section.

Thanks Marc. Will do.

Bruce.


SenderX

unread,
Feb 26, 2005, 8:19:04 AM2/26/05
to
> I'm trying to replace a Mutex semaphore (used to protect a memory resident
> database) with something faster (and hopefully as simple to use), and
> Metered Sections have been suggested.
>
> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_metrsect.asp
>
> but I'm having trouble understanding the description of how to properly
> use it.

Stay away from metered section. Its a poorly designed semaphore. Use this
simple algorithm:


volatile LONG state; // set to initial sema value
HANDLE waitset; // semaphore set to 0


inc()
{
if ( InterlockedIncrement( &state ) < 1 )
{
ReleaseSemaphore( waitset, 1, 0 );
}
}


dec()
{
if ( InterlockedDecrement( &state ) < 0 )
{
WaitForSingleObject( waitset, INFINITE );
}
}

--
http://appcore.home.comcast.net/
(portable lock-free data-structures)


Bruce Chastain

unread,
Feb 28, 2005, 3:51:14 PM2/28/05
to
"SenderX" <x...@xxx.com> wrote in message
news:5eednfqHgYX...@comcast.com...

> Stay away from metered section. Its a poorly designed semaphore. Use this
> simple algorithm:
>
>
> volatile LONG state; // set to initial sema value
> HANDLE waitset; // semaphore set to 0
>
>
> inc()
> {
> if ( InterlockedIncrement( &state ) < 1 )
> {
> ReleaseSemaphore( waitset, 1, 0 );
> }
> }
>
>
> dec()
> {
> if ( InterlockedDecrement( &state ) < 0 )
> {
> WaitForSingleObject( waitset, INFINITE );
> }
> }

Thanks for the code!

Bruce.


Bruce Chastain

unread,
Feb 28, 2005, 3:56:13 PM2/28/05
to
"SenderX" <x...@xxx.com> wrote in message
news:5eednfqHgYX...@comcast.com...
> Stay away from metered section. Its a poorly designed semaphore. Use this
> simple algorithm:

BTW, do you have any comments about the COptex "solution", also mentioned?

Bruce.


Bruce Chastain

unread,
Feb 28, 2005, 4:41:40 PM2/28/05
to
"SenderX" <x...@xxx.com> wrote in message
news:5eednfqHgYX...@comcast.com...
> Stay away from metered section. Its a poorly designed semaphore. Use this
> simple algorithm:
>
>
> volatile LONG state; // set to initial sema value
> HANDLE waitset; // semaphore set to 0
>
>
> inc()
> {
> if ( InterlockedIncrement( &state ) < 1 )
> {
> ReleaseSemaphore( waitset, 1, 0 );
> }
> }
>
>
> dec()
> {
> if ( InterlockedDecrement( &state ) < 0 )
> {
> WaitForSingleObject( waitset, INFINITE );
> }
> }

I replied too soon. The more I look at your code, the less I understand how
it would work.

Presumably, the "dec" is the equivalent of "enter" because it has the
WaitForSingleObject(), and "inc" is the equivalent to "leave" because it has
the ReleaseSemaphore();

Assuming that the initial value of the "state" flag is zero, the first call
to "dec" would result in the WaitForSingleObject() being executed, which
would then wait forever given that we haven't released it yet.

I'm confused!

Bruce.


SenderX

unread,
Feb 28, 2005, 6:14:42 PM2/28/05
to
> Assuming that the initial value of the "state" flag is zero, the first
> call to "dec" would result in the WaitForSingleObject() being executed,
> which would then wait forever given that we haven't released it yet.
>
> I'm confused!

The code I posted "is a semaphore", "not a mutex". If you want to use it as
a mutex, the initial semaphore value ( state flag ) MUST be 1. Here is a
working example of a mutex based on the fast semaphore:


// notice how mutex_from_semaphore inits fast_semaphore to 1???


class fast_semaphore
{

public:

fast_semaphore( LONG init )
: m_state( init ),
m_waitset( CreateSemaphore( 0, 0, LONG_MAX, 0 ) )
{ if ( ! m_waitset ) { throw; } }

~fast_semaphore()
{ if ( ! CloseHandle( m_waitset ) ) { abort(); } }


public:

void inc()
{
if ( InterlockedIncrement( &m_state ) < 1 )
{
if ( ! ReleaseSemaphore( m_waitset, 1, 0 ) )
{
throw;
}
}
}


void dec()
{
if ( InterlockedDecrement( &m_state ) < 0 )
{
if ( WaitForSingleObject( m_waitset, INFINITE ) !=
WAIT_OBJECT_0 )
{
throw;
}
}
}


private:

volatile LONG m_state;
HANDLE m_waitset;

};


class mutex_from_semaphore
{

public:

mutex_from_semaphore() : m_waitset( 1 ) {}


public:

void enter() { m_waitset.dec(); }
void leave() { m_waitset.inc(); }


private:

fast_semaphore m_waitset;

};


See how setting the initial semaphore value to 1, you can get the exact same
results as a mutex?


Bruce Chastain

unread,
Mar 1, 2005, 11:42:35 AM3/1/05
to
"SenderX" <x...@xxx.com> wrote in message
news:2rSdnWWk_fx...@comcast.com...

> The code I posted "is a semaphore", "not a mutex". If you want to use it
> as a mutex,

Yes, I need the functional equivalant to a mutex to protect some shared
memory.

> the initial semaphore value ( state flag ) MUST be 1. Here is a working
> example of a mutex based on the fast semaphore:
>
> // notice how mutex_from_semaphore inits fast_semaphore to 1???

Ah, I think I see that now. Yes, I think that's closer to the mutex
operation I need.

In this case m_state will be initialized to 1, so the first call to
enter/dec will decrement m_state to zero and so thus skip the call to
WaitForSingleObject.

Any subsequent calls to enter/dec will make m_state (more) negative and so
they'll wait on the semaphore to be signaled.

Except for the last call, calls to leave/inc will invoke the
ReleaseSemaphore. The last call to leave/inc will increment m_state back to
1 and so skip the ReleaseSemaphore.

One thing still confuses me I think. The final goal I'm after is a cross
process mutex (actually, more a cross process critical section), so I'm
assuming m_state must be in shared memory and the m_waitset semaphore be a
named semaphore? It appears that the snippet you posted looks like it would
work intra-process only, not inter-process.

Thanks for the help!
Bruce.


SenderX

unread,
Mar 1, 2005, 4:48:23 PM3/1/05
to
>> // notice how mutex_from_semaphore inits fast_semaphore to 1???
>
> Ah, I think I see that now. Yes, I think that's closer to the mutex
> operation I need.
>
> In this case m_state will be initialized to 1, so the first call to
> enter/dec will decrement m_state to zero and so thus skip the call to
> WaitForSingleObject.
>
> Any subsequent calls to enter/dec will make m_state (more) negative and so
> they'll wait on the semaphore to be signaled.
>
> Except for the last call, calls to leave/inc will invoke the
> ReleaseSemaphore. The last call to leave/inc will increment m_state back
> to 1 and so skip the ReleaseSemaphore.

Correct.


> One thing still confuses me I think. The final goal I'm after is a cross
> process mutex (actually, more a cross process critical section), so I'm
> assuming m_state must be in shared memory and the m_waitset semaphore be a
> named semaphore?

Yes.


> The final goal I'm after is a cross process mutex (actually, more a cross
> process critical section)

ok. I thought you needed a semaphore because you asked about metered
sections. You would not really want to use the posted semaphore for a mutex.
fast_semaphore is designed to be used for queues, stackes, ect... Also,
fast_semaphore handles contention by handing off ownership to a waiting
thread in m_waitset. In other words, a full contention-interval is handled
entirely by the kernel. This makes contention-intervals fairly expensive.
Look at this mutex algorithm:


class fast_mutex
{

public:

fast_mutex
: m_state( 0 ),
m_waitset( CreateEvent( 0, FALSE, FALSE 0 ) )


{ if ( ! m_waitset ) { throw; } }

~fast_mutex


{ if ( ! CloseHandle( m_waitset ) ) { abort(); } }


public:

void enter
{
if ( InterlockedExchange( &m_state, 1 ) )
{
_asm pause; /* masm */

while ( InterlockedExchange( &m_state, 2 ) )
{
if ( WaitForSingleObject


( m_waitset,
INFINITE ) !=
WAIT_OBJECT_0 )
{
throw;
}
}
}
}


void leave()
{
if ( InterlockedExchange( &m_state, 0 ) == 2 )
{
if ( ! SetEvent( m_waitset ) )
{
throw;
}
}
}


private:

volatile LONG m_state;
HANDLE m_waitset;

};


This mutex does not handoff ownership because another thread can lock the
mutex during a contention-interval. It improves the throughput of the mutex
during periods of contention.


Vladimir_petter

unread,
Mar 1, 2005, 5:52:45 PM3/1/05
to
Hello Bruce,

One of the problems you might encounter with metered section is that is
stays unreleased if the process that locked it dies for some reason. Unlike
metered section mutex is getting released if a thread that locked it exits /
dies.

Vladimir.

"Bruce Chastain" <bcha...@XNOSPAMXhyperfeed.com> wrote in message
news:eJGW22qG...@TK2MSFTNGP12.phx.gbl...

Bruce Chastain

unread,
Mar 2, 2005, 10:08:36 AM3/2/05
to
"Vladimir_petter" <vla...@hotmail.com> wrote in message
news:ecGr5HrH...@TK2MSFTNGP09.phx.gbl...

> One of the problems you might encounter with metered section is that is
> stays unreleased if the process that locked it dies for some reason.
> Unlike metered section mutex is getting released if a thread that locked
> it exits / dies.

Yes, I've been worrying about that. For performance reasons, I NEED to use
something faster than a mutex, but I find anything, including metered
sections and COptex, that would gracefully handle a process that died while
owning the lock.

The result would leave the lock locked and that would be bad news for the
rest of the processes also using the shared memory.

Is there a solution or am I stuck with Mutexs?

Bruce.


Bruce Chastain

unread,
Mar 2, 2005, 11:05:43 AM3/2/05
to
"SenderX" <x...@xxx.com> wrote in message
news:9a6dncYoS4C...@comcast.com...

> ok. I thought you needed a semaphore because you asked about metered
> sections.

Sorry for the confusion. Someone else suggested the metered section (and
COptex) to me early on in this thread. My goal is really just the
functional evivilance of a cross-process critical section. Something WAY
faster than Mutexes, but usable for multiple thread/process mutual
exclusion.

> You would not really want to use the posted semaphore for a mutex.
> fast_semaphore is designed to be used for queues, stackes, ect... Also,
> fast_semaphore handles contention by handing off ownership to a waiting
> thread in m_waitset. In other words, a full contention-interval is handled
> entirely by the kernel. This makes contention-intervals fairly expensive.

Ok, I think I understand what you mean by that. In our case, contentions
would probably be relatively rare.

> This mutex does not handoff ownership because another thread can lock the
> mutex during a contention-interval. It improves the throughput of the
> mutex during periods of contention.

I don't really understand what you mean by that, but hopefully the light
will come on if I study the code for a while.

As a side comment, considering how miserably slow Mutexes are, I'm really
amazed that MS hasn't come up with a cross-process solution long ago.

I remember one solution under OS/2 called Fast Safe RAM Semaphores that
worked very well.

Slava M. Usov

unread,
Mar 2, 2005, 11:37:22 AM3/2/05
to
"Bruce Chastain" <bcha...@XNOSPAMXhyperfeed.com> wrote in message
news:#HU10lzH...@TK2MSFTNGP12.phx.gbl...

[...]

> The result would leave the lock locked and that would be bad news for the
> rest of the processes also using the shared memory.
>
> Is there a solution or am I stuck with Mutexs?

"Process dies" is actually as good as it can be. "Process hangs" is much
nastier. "Process misbehaves" (e.g., by trashing the lock in shared memory)
cannot be mitigated at all.

Can you reasonably expect that your processes will not hang, will not
misbehave, but may only unexpectedly die?

S


Bruce Chastain

unread,
Mar 2, 2005, 12:12:54 PM3/2/05
to
"Slava M. Usov" <stripit...@gmx.net> wrote in message
news:%23t0ezY0...@TK2MSFTNGP09.phx.gbl...

> Can you reasonably expect that your processes will not hang, will not
> misbehave, but may only unexpectedly die?

In our case, a process misbehaving or hanging would always end up as a
process being terminated because the operator would kill the
misbehaving/hung process using the task manager (and then restart it).

So in the event of a process being killed by the task manager, or (in
another case) dieing due to an exception, I would expect the other processes
to continue as if nothing had happened, as they do now.

I believe in the case of an real Mutex, other processes receive a
WAIT_ABANDONED, indicating that the owning thread had died, and so would
continue.

But I'm not clear on how a fast_mutex would fair if a thread/process that
owned it died before releasing it (leave). Would the additional processes
be forced to wait forever for some event that would never happen?

Slava M. Usov

unread,
Mar 2, 2005, 12:33:25 PM3/2/05
to
"Bruce Chastain" <bcha...@XNOSPAMXhyperfeed.com> wrote in message
news:OgH2Tr0H...@TK2MSFTNGP09.phx.gbl...

> In our case, a process misbehaving or hanging would always end up as a
> process being terminated because the operator would kill the
> misbehaving/hung process using the task manager (and then restart it).
>
> So in the event of a process being killed by the task manager, or (in
> another case) dieing due to an exception, I would expect the other
> processes to continue as if nothing had happened, as they do now.

If the misbehaving process has damaged the shared area, then the other
processes may find it difficult to continue as if nothing had happened.

> But I'm not clear on how a fast_mutex would fair if a thread/process that
> owned it died before releasing it (leave). Would the additional processes
> be forced to wait forever for some event that would never happen?

If that fast_mutex is a variable in shared memory plus an event or
something, yes.

Are all the processes in question part of one application? In that case, you
might have a process monitor that will reset the mutex when a process dies
unexpectedly -- but you'll have to keep track of the mutex ownership in this
case. Even simpler, the monitor may just re-start the other processes in
such a case.

S


Vladimir_petter

unread,
Mar 2, 2005, 12:35:12 PM3/2/05
to
[skip]

> But I'm not clear on how a fast_mutex would fair if a thread/process that
> owned it died before releasing it (leave). Would the additional processes
> be forced to wait forever for some event that would never happen?

Yes, unfortunately that is the case. This problem does not have a solution
since there is no a 3rd party (like OS kernel) that would step in at the
moment when one of the processes dies and clean-up after it.

You may try to do that by introducing a monitor (a process or a thread)
that would be somehow aware of all the opened metered sections, and will be
checking if the process/thread that locked this section is still alive, and
perform a clean up if it dies.
I am not sure if this is doable and how much overhead it will introduce.

I am not sure what is the nature of the problem you are trying to solve, but
one of the directions you may try to move to is to avoid shared data
whatsoever. Use producer consumer with a lok-free queue inside.

Vladimir.

Bruce Chastain

unread,
Mar 2, 2005, 3:24:47 PM3/2/05
to
"Vladimir_petter" <vla...@hotmail.com> wrote in message
news:%236HmH70...@TK2MSFTNGP15.phx.gbl...

> I am not sure what is the nature of the problem you are trying to solve,
> but one of the directions you may try to move to is to avoid shared data
> whatsoever. Use producer consumer with a lok-free queue inside.

I'm trying to solve a performance problem associated with the use of a mutex
to protect a shared memory database (it's a red/black database structure in
shared memory).

FYI, these shared memory databases are accessed via a published api (dba())
in an sdk we distribute to out customers. Most of the apps that use the api
are ours, but some are not.

The databases are updated from real time stock market information that
already exceeds 100,000 messages per second, and that increases about 50%
every 9 months or so.

In trying to increase the performance of our apps (those that use the
databases and those that update them), I ran the code profiler to see where
all our CPU cycles are going. The code profiler shows we spend 99% of the
app time in our database api, and 2/3rds of that time on just 2 lines in the
api:

WaitForSingleEvent()
ReleaseMutex()

In other words, about 2/3rd of out CPU cycles are currently being "wasted"
just acquiring and releasing the mutex that protects the shared memory
database.

If I can find an acceptable mutiprocess substitute for the protection mutex,
our apps would increase in speed by up to several hundred percent. Since
we're in a real time "keep up or die" data business, that's absolutely
critical to us, and we're already running on the fastest iron made.

Thanks for any thoughts!
Bruce.


Bruce Chastain

unread,
Mar 2, 2005, 3:40:54 PM3/2/05
to
"SenderX" <x...@xxx.com> wrote in message
news:9a6dncYoS4C...@comcast.com...

One question about your code. What does:

_asm pause; /* masm */

do?

Thanks,
Bruce.


Bruce Chastain

unread,
Mar 2, 2005, 4:39:53 PM3/2/05
to
"Slava M. Usov" <stripit...@gmx.net> wrote in message
news:edkqH40H...@TK2MSFTNGP15.phx.gbl...

> Are all the processes in question part of one application?

Nope. Most are ours but some are written to our api by our customers.

Bruce.


Vladimir_petter

unread,
Mar 2, 2005, 5:22:15 PM3/2/05
to
I am wondering if a read operation on the data happening much more often
then write operation. In that case "single writer - multiple readers"
synchronization object would be a right way to go, but unfortunately NT does
not provide one and the one that I have suffers from the same problem as
metered section :(

Another way to go would be to study if the storage can be splitted to
several independent partitions and each of them would be protected by its
own mutex.

Vladimir.


"Bruce Chastain" <bcha...@XNOSPAMXhyperfeed.com> wrote in message

news:OaD9fW2H...@tk2msftngp13.phx.gbl...

Isaac Chen

unread,
Mar 2, 2005, 11:10:25 PM3/2/05
to
If a process dies while owning the lock, the entity that lock protects
is most likely in an inconsistent state. So you have a bigger problem to
solve than worrying about "the rest of the processes" being blocked.
They'd better not touch the entity (RAM DB in your case) anyway!

But if you are sure inconsistency would not happen* even some
process dies in the "critical section", then a monitor plus the tracking
of the ownership of the lock (like others have suggested) is needed.

* which is not likely, or the lock is not really needed in the first place.

Isaac Chen

"Bruce Chastain" <bcha...@XNOSPAMXhyperfeed.com> wrote in message

news:%23HU10lz...@TK2MSFTNGP12.phx.gbl...

Isaac Chen

unread,
Mar 3, 2005, 12:40:45 AM3/3/05
to
"SenderX" <x...@xxx.com> wrote in message
news:9a6dncYoS4C...@comcast.com...

> > The final goal I'm after is a cross process mutex (actually, more a
cross
> > process critical section)
>
> ok. I thought you needed a semaphore because you asked about metered
> sections. You would not really want to use the posted semaphore for a
mutex.
> fast_semaphore is designed to be used for queues, stackes, ect... Also,
> fast_semaphore handles contention by handing off ownership to a waiting
> thread in m_waitset. In other words, a full contention-interval is handled
> entirely by the kernel. This makes contention-intervals fairly expensive.

"handles contention by handing off ownership to a waiting thread in
m_waitset"

Do you mean, in Win32, "ReleaseSemaphore" (or "LeaveCriticalSection" as
you mentioned in another thread) will triger a context switch if there's any
"WaitForSingleObject" (or "EnterCriticalSection") blocks on the related
synchronization object somewhere else in the system?

If so, is this behavior documented? Or you learnt that other way?

Thank you.

Isaac Chen

SenderX

unread,
Mar 3, 2005, 4:07:09 AM3/3/05
to
> "handles contention by handing off ownership to a waiting thread in
> m_waitset"
>
> Do you mean, in Win32, "ReleaseSemaphore" (or "LeaveCriticalSection" as
> you mentioned in another thread) will triger a context switch if there's
> any
> "WaitForSingleObject" (or "EnterCriticalSection") blocks on the related
> synchronization object somewhere else in the system?

Take the mutex_from_semaphore object I posted as an example, then I will
point you to a thread where a guy who works on windows kernel says that
CRITICAL_SECTION's do indeed hand off ownership. Here is why the passing of
ownership wrt mutex's can be expensive...

Think of four threads hitting mutex_from_semaphore at the same time. Lets
say the sequence of events goes as follows:


1. thread A locks. transition:( 1 -> 0 )
2. thread B blocks. transition:( 0 -> -1 )
3. thread C blocks. transition:( -1 -> -2 )
4. thread D blocks. transition:( -2 -> -3 )

As of now, the current contention-interval has 3 waiting threads. Now, lets
see what happens when thread A begins to destroy the contention-interval.


1. thread A unlocks. transition:( -3 -> -2 )
2. thread A signals unknown thread in waitset...

The state transition ( -3 -> -2 ) means that a signal to the waitset is
necessary. An unknown thread ( lets call it thread X ) that's in the current
waitset now "owns" the mutex. Thread X has to receive the signal and start
to run "before any forward progress can occur". Forward progress was
basically transferred from Thread A to Thread X across a context-switch.
This process is repeated until state transition: ( 0 -> 1 ) which indicates
the end of the current contention-interval.


>
> If so, is this behavior documented? Or you learnt that other way?

http://groups-beta.google.com/group/comp.programming.threads/msg/5354a3b6b0753932
( read all )


SenderX

unread,
Mar 3, 2005, 4:11:44 AM3/3/05
to
> Yes, I've been worrying about that. For performance reasons, I NEED to
> use something faster than a mutex, but I find anything, including metered
> sections and COptex, that would gracefully handle a process that died
> while owning the lock.
>
> The result would leave the lock locked and that would be bad news for the
> rest of the processes also using the shared memory.
>
> Is there a solution or am I stuck with Mutexs?

If the owner of a mutex screws up and dies for some reason, I would consider
"anything" guarded by the mutex to be in an unstable state. IMHO, a cold
deadlock is a lot easier to debug than a crash caused by working on
corrupted shared data...


SenderX

unread,
Mar 3, 2005, 4:26:54 AM3/3/05
to
>> Stay away from metered section. Its a poorly designed semaphore. Use this
>> simple algorithm:
>
> BTW, do you have any comments about the COptex "solution", also mentioned?

It uses a spinlock to protect its internal state. A mutex or semaphore
algorithm does not require locks to protect its internal state. This renders
COptex sub-optimal. Also, it handles recursion in an odd way. There is no
need for any atomic operations to implement recursion.


Slava M. Usov

unread,
Mar 3, 2005, 6:17:53 AM3/3/05
to
"Bruce Chastain" <bcha...@XNOSPAMXhyperfeed.com> wrote in message
news:#jSleA3H...@TK2MSFTNGP14.phx.gbl...

If you can change the API, you could have a 'register subscriber' API that
connects any process to the monitor. The monitor then allocates a unique ID
for each registered process and communicates it to the process. Each shared
mutex has an 'owner' field: when a process locks the mutex, it stores its ID
in that field. When a registered process exits, the monitor inspects each
shared mutex and for each one whose owner ID is that of the dead process, it
signals the event/semaphore. The process that completes the wait will
discover that the owner field is not zero, which effectively means
'abandoned mutex'.

However, handling inconsistent data seems to be a bigger problem, more so
because you have multiply-linked data.

S


Bruce Chastain

unread,
Mar 3, 2005, 9:25:52 AM3/3/05
to
"SenderX" <x...@xxx.com> wrote in message
news:7v2dnR8P4qP...@comcast.com...

> It uses a spinlock to protect its internal state. A mutex or semaphore
> algorithm does not require locks to protect its internal state. This
> renders COptex sub-optimal. Also, it handles recursion in an odd way.
> There is no need for any atomic operations to implement recursion.

Thanks. I appreciate your comments and help!

Bruce.


Bruce Chastain

unread,
Mar 3, 2005, 10:52:44 AM3/3/05
to
"Vladimir_petter" <vla...@hotmail.com> wrote in message
news:ehSShb3H...@TK2MSFTNGP15.phx.gbl...

> Another way to go would be to study if the storage can be splitted to
> several independent partitions and each of them would be protected by its
> own mutex.

I'm not sure how multiple mutexs would help. Since we probably have very
little contention for the shared memory mutex, having multiple mutexes
probably wouldn't buy us much, if anything. I'd still be "wasting" 2/3rds
of our CPU time on the lines:

WaitForSingleObject()
ReleaseMutex()

Bruce.


Pavel Lebedinsky

unread,
Mar 4, 2005, 1:51:42 AM3/4/05
to
"SenderX" wrote:

> Take the mutex_from_semaphore object I posted as an example, then I will
> point you to a thread where a guy who works on windows kernel says that
> CRITICAL_SECTION's do indeed hand off ownership.

This has been fixed in Win2003 SP1.


Isaac Chen

unread,
Mar 4, 2005, 3:29:06 AM3/4/05
to
After reading SenderX's description and the news group thread
he mentioned, I'm still not sure if I understand what "handing off
ownership" means.

Seems to me "handing off" (passing on) ownership doesn't trigger
context switch immediately. The thread which just released its
critical_section can still run till
a) the end of its quantum, or
b) preempted by higher priority thread, or
c) blocked on a synchronization object (including that critical_section)
If the ownership is not passed on, some threads might be starved!

If that's indeed the case, then what exactly has been fixed in
Win2003 SP1? A performance bug (in previous Windows)?

Or maybe I simply misunderstood "handing off ownership"?

Thank you.

Isaac Chen

"Pavel Lebedinsky" <m_pll at hotmail com> wrote in message
news:eopieaI...@TK2MSFTNGP15.phx.gbl...

Pavel Lebedinsky

unread,
Mar 4, 2005, 4:27:34 AM3/4/05
to
"Isaac Chen" wrote:

> If the ownership is not passed on, some threads might be starved!

Not passing ownership means that new threads trying to lock
the critical section might be able to proceed without having
to wait for all currently blocked waiters. The waiters will
eventually be scheduled though, and when they are scheduled
they will be just as likely to block as any other thread, so in
practice startvation should be unlikely.

> If that's indeed the case, then what exactly has been fixed in
> Win2003 SP1? A performance bug (in previous Windows)?

It's a performance improvement, but it should only matter
when there's lots of contention, so you could argue that
the applications that will benefit from it are not very well
designed in the first place. Unfortunately, that probably
describes most of the real world applications.


SenderX

unread,
Mar 5, 2005, 1:39:34 PM3/5/05
to
> One question about your code. What does:
>
> _asm pause; /* masm */
>
> do?

It basically renders spinlocks hyperthread friendly by introducing a slight
delay. I used it here because there is two atomic ops in a row that might
not lock the mutex. A pause in-between them is appropriate in this case.
Study the Intel manuals for more info.


Isaac Chen

unread,
Mar 9, 2005, 10:45:55 PM3/9/05
to
"...because there is two atomic ops in a row that might not lock the mutex"
Can you elaborate?

BTW, I saw the use of 'pause' mentioned in a optimization doc from Intel
in the context of a spin-wait loop similar to the following:

do
_asm pause;
while (lock != 0);
// ...

But I couldn't find any example/explanation in the way you use it. Can you
please point me a specific doc regarding that?

Thank you.

Isaac Chen

"SenderX" <x...@xxx.com> wrote in message

news:86mdnZd3E6V...@comcast.com...

0 new messages