Re: Synchronization exception

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



On Mon, 05 Jan 2009 14:01:01 -0700, David <DavidLBlackDeck@xxxxxxxxxxxxxxxx> wrote:

[...]
What is an "unsynchronized" block of code?

That's the error you get if you try call a method that requires the calling thread to own the synchronization object when the calling thread doesn't actually own the synchronization object.

Calling Monitor.Exit() when you haven't called Monitor.Enter() would be an example of that, but there are other ways to get the exception too.

I'm confident that you can't hit
the Exit method without having hit the Enter method two lines before,

Certainly the code you posted doesn't appear to be able to in and of itself generate the exception you describe. It has some bugs (a synchronization bug in the setter, and both the getter and setter may return without releasing the lock, if an exception were to occur...the latter bug being more an issue in the setter where you call to another method). But I don't think those would cause the exception you're seeing.

The problem is, you posted only a tiny amount of the actual code. Without a concise-but-complete code sample that reliably reproduces the problem, there's no way for anyone else to know what you've done wrong. We can only tell you that you have in fact done something wrong.

so the
lock owner really should be the thread in question every time. The Help file
says that the thread calling Exit() must be the owner of the lock. Is the
"owner" of the lock the thread that called Enter()? That's what I assume,
but it's obvious that in this case, you can only get to the ExitI() method
after calling the Enter() method, so doesn't that make that thread the owner?

All of that is true, which means that you've left out some important piece of information. After all, you _are_ getting the exception.

Please create a concise-but-complete code sample that reliably reproduces the problem, and I or someone else will gladly look at it and try to determine what's wrong with the code.

In the meantime, here's an example of a more elegant way to implement the property as you've posted it:

private object objLock = new object();
private CycleStates vCurrentCycleState;

public CycleStates CurrentCycleState
{
get
{
lock (objLock)
{
return vCurrentCycleState;
}
}

set
{
lock (objLock)
{
if (value != vCurrentCycleState)
{
switch (value)
{
case CycleStates.ActiveState:
Activate();
break;
case CycleStates.InactiveState:
DeActivate();
break;
}

vCurrentCycleState = value;
}
}
}
}

The C# "lock" statement is basically a way to use Monitor.Enter()/Exit() in a safe, concise way. In particular, it is not possible to exit the block of code protected by the "lock" statement without releasing the lock (it essentially uses a try/finally around the block).

I changed the setter so that the code gets the lock before inspecting the variable of interest. This ensures that another thread trying to set the value at the same time won't result in erroneous duplicated activate/deactivate calls, as well as simply ensuring that the variable is actually set as expected.

I also introduced a new variable for locking. It is generally a better idea to not use the object being synchronized as the actual synchronization reference, because if you do use the object as the synchronization reference, that opens the possibility of some other code also using it as a synchronization reference without your knowledge. At best, this could cause unintended contention for the lock, and at worst, it could result in a difficult-to-debug deadlock scenario.

One thing I left along was the order in which you update the variable relative to calling the activate/deactivate methods. You should be aware that in all of the .NET classes I can think of off the top of my head, a property is updated _before_ calling a method that signals the update, so that when that method is called, the new value is available. The inconsistency between your code and the .NET convention could lead to maintenance issues, so you should be very sure this is really how you want/need it to be.

Finally, I simply assigned the property value to the variable in the setter; in your original code, you assign a value other than the one passed in, which would result in your code getting repeated calls to Activate every time you try to assign CycleStates.ActiveState to the property (since the new value wouldn't wind up being the one being assigned, your test to see if the current value is the same as being assigned would always fail).

Without knowing anything about the rest of the code, I can't say for sure that the last change described above is actually correct. However, if it's not correct in your eyes, then I would strongly suggest your broader design may be flawed, as the behavior implemented in your original code certainly is unusual and counter-intuitive (a situation that leads to hard-to-maintain code).

Pete
.



Relevant Pages

  • Re: Multi Threading Options
    ... If the avatars struct could be modified by any other thread, ... your modifications are so short that releasing the main lock and locking just ... Given that the refresh is timer=based, you could probably eliminate all synchronization ... If it is a UI thread, then while the drawing is happening, the PostMessage ...
    (microsoft.public.vc.mfc)
  • Re: threading - Monitor.Wait/Pulse
    ... thread synchronization is considered a "Bad Thing" since there is no way ... WaitOne/WaitAny/WaitAllmethods of the WaitHandle indicates whether ... don't get with WaitHandles is that it releases the Lock on the Object ... RendezvousDemo demo = new RendezvousDemo; ...
    (microsoft.public.dotnet.general)
  • Re: Why "lock" functionality is introduced for all the objects?
    ... very nature of objects in Java. ... synchronization, well, simple. ... can use it as a lock (strictly speaking, a Hoare monitor). ...
    (comp.lang.java.programmer)
  • Re: multithreaded tcp/ip monitoring application
    ... I used the "lock" synchronization mechanism to manage a shared arraylist object. ... So it would be better to have the network i/o code initiate the UI update. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Independent thread fireing events in ATL Service synchronization requirements?
    ... and made my client list a class with synchronization inside ... my guess is that the lock for the COM object ... pointer is not enough and that I would also need to lock ... > the entire loop notifying your objects. ...
    (microsoft.public.vc.atl)