Hmm, I had been thinking of

if (bNeedInit)
{
  lock(this)
  {
    if (bNeedInit)
    {
      lock(this)
      {
        <init stuff>
      }
      bNeedInit = false;
    }
  }
}

I agree with you that there was still a problem in the code I posted
(although you must admit that it would safely initialize the value of
variable bNeedInit ;-). About threads, sure they can hop across cpu's.
However, the point was of course that while a thread is scheduled, it will
run on one cpu only. Context switches surely don't alter the code sequence
being executed ;-). I agree with you on your point that memory access from
one cpu to one mem location is not reordered. That's the rule I was
referring to.

So, what can we learn from this: never post code from the top of your head
and then respond to emails without rereading what you posted ;-);-).

-- Henkk

----- Original Message -----
From: "Valery Pryamikov" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Monday, April 29, 2002 1:34 PM
Subject: Re: [DOTNET] lock - how expensive is it to call?


> BTW:
> This kind of lazy init problem could be corrected following way:
>
> if (fNeedInit)  {
>         lock (this) {
>                 if (fNeedInitInt) {
>                         <init stuff>
>                         fNeedInitInt = false;
>                 }
>         } //write barrier is performed by lock's release.
>         fNeedInit = false;
> }
>
> Note: second if checks internal fNeedInitInt variable and fNeedInit is
> updated outside of lock region.
> (of course we consider that bNeedInit/fNeedInit/fNeedInitInt are not
> volatile).
>
> -Valery.
>
> -----Original Message-----
> From: Valery Pryamikov
> Sent: Monday, April 29, 2002 11:55 AM
> To: 'dotnet discussion'
> Subject: RE: Re: [DOTNET] lock - how expensive is it to call?
>
> Henk,
> Here are some problems:
> 1. Execution of the code on the same thread doesn't necessaraly mean
> execution of the code on the same processor.
> 2. Dotnet memory model guarantees that reads and writes from the same
> processor to the *same memory location* would never cross each other,
> but no guarantees about read/write to the different memory locations.
> 3. Even so bNeedInit assignment is atomic, but there is no guarantee
> that it will be visible to other processors in the same order as
> preceding assignments during <init stuff>.
>
> if (bNeedInit)  {
>         lock(this) {
>         if (bNeedInit) {
>                 <init stuff>
>                 bNeedInit = false;
>                 //<--your code is vulnerable right here
>                 // other processors could already see bNeedInit value is
> false,
>                 // but previous assignments during <init stuff> could
> still be
>                 // not available to the other processors.
>                 // memory barrier will be placed during exit from lock
> block
>                 // on the next line.
>           }
>         } // exits lock with all necessary memory barriers
> ...
>
> -Valery.
>
> P.S. of course your code is guaranteed to work on X86 architecture due
> to stronger memory model there.
>
> -----Original Message-----
> From: Henk de Koning [mailto:[EMAIL PROTECTED]]
> Sent: Monday, April 29, 2002 10:53 AM
> To: [EMAIL PROTECTED]
> Subject: Re: [DOTNET] lock - how expensive is it to call?
>
> Although I agree with you that there's more to synchronization in .Net
> than meets the eye (is this correct English btw ?), I don't think
> there's a problem with the code I posted. Here's why:
>
> 1) locks are internally implemented with volatile reads and writes
> (which makes tons of sense ;-)
> 2) according to the CLR memory model, reads and writes from the same
> processor will never cross each other
> 3) read/write reordening will never cross locks (they're implemented
> using
> volatile)
> 4) all instructions in a sync'ed block of code will run on one thread
> and hence on one processor
>
> QED
>
> -- Henkk
>
> BTW, the problem you mention is very real and exactly the reason I
> forked off the 'finding out if we need initialization' to a separate
> (valuetype) variable. BTW2, the C# volatile keyword is generally too
> rigid as it will cause *all* reads and writes to the variable to be
> volatile BTW3, bNeedInit is *not* a class with an implicit conversion
> operator for bool ;-)
>
> ----- Original Message -----
> From: "Ian Griffiths" <[EMAIL PROTECTED]>
> To: <[EMAIL PROTECTED]>
> Sent: Sunday, April 28, 2002 12:24 AM
> Subject: Re: [DOTNET] lock - how expensive is it to call?
>
>
> > "Henk de Koning" wrote:
> >
> >
> > >     if (bNeedInit) {
> > >         lock(this) {
> > >             if (bNeedInit) {
> > >                 <init stuff>
> > >                 bNeedInit = false;
> > >             }
> >
>
> You can read messages from the DOTNET archive, unsubscribe from DOTNET, or
> subscribe to other DevelopMentor lists at http://discuss.develop.com.
>

You can read messages from the DOTNET archive, unsubscribe from DOTNET, or
subscribe to other DevelopMentor lists at http://discuss.develop.com.

Reply via email to