Home All Groups Group Topic Archive Search About

pseudo spin-lock design help

Author
21 Dec 2006 8:37 PM
mpaine
Hi everyone,

I wrote some code and it seems ok to me but since it is going into a
high-use production environment, I wanted some peer-review if possible.
Basically, I wanted a way to know if an object is being "reset" and
only allow one thread to reset it at any one time.  This is what I came
up with:

            Private _lockResetSync As Object = New Object()
            Private _lockResetWaitEvent As ManualResetEvent = New
ManualResetEvent(False)
            Private _IsResetting As Boolean = False
            Public Sub Reset(ByVal cmd As Object)
                Dim _ThisThreadIsResetting As Boolean = False
                While Not _ThisThreadIsResetting ' pseudo-spin-lock for
thread safety
                    If _IsResetting Then
                        _lockResetWaitEvent.WaitOne()
                        Exit Sub
                    End If
                    SyncLock _lockResetSync
                        If Not _IsResetting Then
                            _lockResetWaitEvent.Reset()
                            _IsResetting = True
                            _ThisThreadIsResetting = True
                        End If
                    End SyncLock
                End While
                Try
            ' !! Do time-consuming thread-safe stuff here
                Finally
                    _IsResetting = False
                    _lockResetWaitEvent.Set()
                End Try
            End Sub
            Public ReadOnly Property IsResetting() As Boolean
                Get
                    Return _IsResetting
                End Get
            End Property

I feel if two threads came into Reset() at the same clock-tick (hehe),
this would still work correctly.  Also, external objects would know
what is going on.  Will this work and if not, what is a better way to
do this?

Thank you,
Michael

Author
22 Dec 2006 7:24 AM
Lucian Wischik
mpa***@htxml.com wrote:
>I wrote some code and it seems ok to me but since it is going into a
>high-use production environment, I wanted some peer-review if possible.

I found your code tortuous to follow. If you want peer-review you'll
need to document it! i.e. write at the top what the specification is
for your code.

Anyway, here's my attempt at a simpler alternative. The specification
is: we have a global variable called "state", which is normally 0
(unset) or 1 (set). It also has a special state 1 (resetting). Only
one thread is allowed to be resetting at any one time, and the
resetting process may be lengthy.

Private state As Integer = 1

Public Sub reset()
  While Interlocked.CompareExchange(state, 2, 1) <> 1
  End While
  ' ...
  Interlocked.CompareExchange(state, 0, 2)
End Sub

Nots on the code: the initial While loop will keep going until we
succeed in being the unique thread who shifts it from 1 to 2. Then the
"..." body proceeds. Within this body, we are guaranteed that we are
the only thread running this body while in state 2. (note: this
guarantee depends on the fact that no one changes the state except
through our own carefully controlled methods). Finally we complete our
resetting by putting it back to 0. This final CompareExchange is
guaranteed to succeed. That's because no one else was able to shift
from state 2 to anything. (but we should probably but a Debug.Assert
there).

Note: it's possible to put a Wait inside the initial while loop, but
not needed. Could even use a Sleep.


--
Lucian
Author
22 Dec 2006 2:02 PM
Lucian Wischik
Lucian Wischik <lu***@wischik.com> wrote:
>0 (unset) or 1 (set). It also has a special state 1 (resetting).

I meant "2 (resetting)" obviously!

--
Lucian
Author
22 Dec 2006 7:29 PM
Chris Mullins
Your "_IsResetting" boolean, is going to cause you major, major, major
trouble. It needs to be marked as volatile (which VB.Net doesn't support,
IIRC) or you need to access it using either the Interlocked operations, the
Thread.VolatileRead/VolatileWrite constructs, or with (don't do this!) a
MemoryBarrier. I didn't really look through the code in any more depth than
that.

Looking through your code, I would strongly suggest you  go pull down Jeff
Richter's Power Threading library from the Wintellect site, and use his
threading constructs. They're already debugged, well documented, and easy to
use.

Writing this level of complexity yourself, when you're not an expert (and
your use of the boolean member says you're not yet an expert), is going to
be an excercise in frustration. It's also going to always (!!) have subtle
bugs in it. These bugs are also a nightmare to track down and debug.

For an example of the type of debugging you'll be stuck doing:
http://www.coversant.net/Default.aspx?tabid=88&EntryID=28

--
Chris Mullilns, MCSD.NET, MCPD:Enterprise
http://www.coversant.net/blogs/cmullins


<mpa***@htxml.com> wrote in message
Show quoteHide quote
news:1166733461.417765.310300@73g2000cwn.googlegroups.com...
>
> Hi everyone,
>
> I wrote some code and it seems ok to me but since it is going into a
> high-use production environment, I wanted some peer-review if possible.
> Basically, I wanted a way to know if an object is being "reset" and
> only allow one thread to reset it at any one time.  This is what I came
> up with:
>
>            Private _lockResetSync As Object = New Object()
>            Private _lockResetWaitEvent As ManualResetEvent = New
> ManualResetEvent(False)
>            Private _IsResetting As Boolean = False
>            Public Sub Reset(ByVal cmd As Object)
>                Dim _ThisThreadIsResetting As Boolean = False
>                While Not _ThisThreadIsResetting ' pseudo-spin-lock for
> thread safety
>                    If _IsResetting Then
>                        _lockResetWaitEvent.WaitOne()
>                        Exit Sub
>                    End If
>                    SyncLock _lockResetSync
>                        If Not _IsResetting Then
>                            _lockResetWaitEvent.Reset()
>                            _IsResetting = True
>                            _ThisThreadIsResetting = True
>                        End If
>                    End SyncLock
>                End While
>                Try
> ' !! Do time-consuming thread-safe stuff here
>                Finally
>                    _IsResetting = False
>                    _lockResetWaitEvent.Set()
>                End Try
>            End Sub
>            Public ReadOnly Property IsResetting() As Boolean
>                Get
>                    Return _IsResetting
>                End Get
>            End Property
>
> I feel if two threads came into Reset() at the same clock-tick (hehe),
> this would still work correctly.  Also, external objects would know
> what is going on.  Will this work and if not, what is a better way to
> do this?
>
> Thank you,
> Michael
>