473,388 Members | 1,286 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,388 software developers and data experts.

Serious Threading.Monitor issues in .NET 2.0

Hi,

I have been looking into the claim that the keyword lock is not safe
when exceptions are possible. That lead me to try the following code,
which I think has uncovered a serious error in the .NET 2.0 framework.
Note that this runs better, but not perfectly, on .NET 1.1.

Note: The numbers are line numbers needed to match the callstack of the
exception below.

// Class WorkItem ...
34 public void DoItSafeLock()
35 {
36 try
37 {
38 Monitor.Enter(this);
39 Thread.Sleep(10);
40 }
41 finally
42 {
43 Monitor.Exit(this); // <-- SynchronizationLockException!
44 }
45 }

Here's what I get when I run this code on a different thread than the
one that created the object holding this method (WorkItem class):

System.Threading.SynchronizationLockException: Object synchronization
method was called from an unsynchronized block of code.
at WorkItems.WorkItem.DoItSafeLock() in
D:\LockTest\WorkItems\WorkItem.cs:line 43
at WorkItems.Worker.ExecuteWorkItem() in
D:\LockTest\WorkItems\Worker.cs:line 127

Notice that the error is that on line 43, the object does not hold a
lock on itself (this). How is this possible given that it made it
through the Monitor.Enter(this) call on line 38?!?

Does any one know what's going on here? How can the monitor be entered
and yet no lock is acquired?

I have a sample application demonstrating the error if any one wants to
see the code, just email me and I'll zip up the solution and send it
your way.

Thanks in advance,
Michael

Michael Kennedy

Nov 30 '05 #1
25 2181
KJ
the problem is locking on "this", don't do it. lock on a private object
instead. then see what happens

Nov 30 '05 #2
Hi KJ,

That is not the problem. It is a best practice to not do this, but it
should not fail .NET's Monitor class. Thanks for the advice though.

Michael

ps - Once classes "other object" is another classes this.

Nov 30 '05 #3
KJ
Could you post all the code (enough to repro)?

Nov 30 '05 #4
Hi KJ,

It's kind of big, across 4 files. Can I email it to you?

Thanks,
Michael

Nov 30 '05 #5
I would post it, so others can look at it as well. Just zip it up.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Michael Kennedy" <mk******@unitedbinary.com> wrote in message
news:11*********************@g44g2000cwa.googlegro ups.com...
Hi KJ,

It's kind of big, across 4 files. Can I email it to you?

Thanks,
Michael

Nov 30 '05 #6
Hi,

Ok, just a second. I'll send it up for you guys.

Michael

Nov 30 '05 #7
Hi Guys,

You can download the solution here:

http://www.unitedbinary.com/TEMP-001...8/LockTest.zip

Let me know what you think,
Michael

Nov 30 '05 #8
Hi KJ,

In case you didn't see the reponse to Nicholas...

You can download the solution here:

http://www.unitedbinary.com/TEMP-001...8/LockTest.zip

Let me know what you think,
Michael

Nov 30 '05 #9
KJ
When you wrote "solution", I thought you meant solution to the problem,
not VS .sln.

I will run this at home later, since I don't have vs2005 on this
machine.

Sorry if my first answer was on the glib side.

Nov 30 '05 #10
Hi KJ,

Thanks. Let me know what you think. I could be missing something, but I
think the code is correct, and yet it's kickin' exceptions out left and
right.

If you want to see what it's output is like without VS.NET 2005, you
could look at the SampleOutput.txt file including in one of the
projects.

Take care,
Michael

Nov 30 '05 #11
You should never call Thread.Abort asynchronously, that is from another
thread than the owning thread, like you do.

When your thread gets aborted when Monitor.Enter(this) (in DoItSafeLock())
is waiting to aquire the lock, the wait will be abandoned and the finally
clause ( so Monitor.Exit( this );) executed, resulting in a
SynchronizationLockException

Willy.

"Michael Kennedy" <mk******@unitedbinary.com> wrote in message
news:11**********************@z14g2000cwz.googlegr oups.com...
Hi KJ,

In case you didn't see the reponse to Nicholas...

You can download the solution here:

http://www.unitedbinary.com/TEMP-001...8/LockTest.zip

Let me know what you think,
Michael

Nov 30 '05 #12
Hi Willy,

That is a valid point. ASP.NET throws thread abort excpetions. Is this
always from the calling thread in ASP.NET?

How can I ensure that a client of my libraries won't do that and
subsequently permanently lock my objects?

Thanks,
Michael

Nov 30 '05 #13

"Michael Kennedy" <mk******@unitedbinary.com> wrote in message
news:11**********************@z14g2000cwz.googlegr oups.com...
Hi Willy,

That is a valid point. ASP.NET throws thread abort excpetions. Is this
always from the calling thread in ASP.NET?

How can I ensure that a client of my libraries won't do that and
subsequently permanently lock my objects?

Thanks,
Michael


ASP.NET only aborts threads as a result of Apllication Domain unloads, that
means that the domain and it's loaded code and objects will be removed
anyway.
Clients of your library code should not abort threads they don't own, this
is true for unmanaged code as well as for managed code.
Note that V2 of the framework contains some reliability features to protect
you from issues resulting from asynchronous thread abort's (proper clean-up
of unmanaged resources and locks), but again this doesn't mean it's safe to
introduce asynchronous thread aborts while continuing to execute code in
that AD.
Please read my reply in the clr NG where you posted the same question.

Willy.


Nov 30 '05 #14
Willy,

That is not true. Response.Redirect(url) or Response.Redirect(url,
true) will also throw thread abort exceptions.

Regards,
Michael

Nov 30 '05 #15
Willy,

One more thing:
Clients of your library code should not abort threads they don't own, this
is true for unmanaged code as well as for managed code.


True, but consider this.

1. Client creates a thread
2. Clent creates an object from my library and interacts with it on
their thread.
3. My objects uses lock properly.
4. Client aborts *their* thread.
5. My object is dead-locked.

Regards,
Michael

Nov 30 '05 #16

"Michael Kennedy" <mk******@unitedbinary.com> wrote in message
news:11*********************@o13g2000cwo.googlegro ups.com...
Willy,

One more thing:
Clients of your library code should not abort threads they don't own,
this
is true for unmanaged code as well as for managed code.


True, but consider this.

1. Client creates a thread
2. Clent creates an object from my library and interacts with it on
their thread.
3. My objects uses lock properly.
4. Client aborts *their* thread.
5. My object is dead-locked.

Regards,
Michael


I said you can only safely call Thread.Abort in the code executing on that
thread (synchronously). A thread started by a client, does not mean the
client owns the thread, it's the thread procedure that owns the thread it's
running in.
That means calling Thread.CurrentThread.Abort() is safe, anything else is
unsafe and should only result from a AD unload.

Willy.


Dec 1 '05 #17

"Michael Kennedy" <mk******@unitedbinary.com> wrote in message
news:11**********************@g47g2000cwa.googlegr oups.com...
Willy,

That is not true. Response.Redirect(url) or Response.Redirect(url,
true) will also throw thread abort exceptions.

Regards,
Michael


Sure, but, Response.Redirect(url) and Response.Redirect(url), do throw a
ThreadAbortException they don't call Thread.Abort().
That means that the CURRENT thread (the one that throws) will terminate as
ThreadAbortException cannot be catch'd, this is totally different from
calling SomeOtherThread.Abort() on another thread, which injects a
ThreadAbortException in "SomeOtherThread" thread.

Willly.
Dec 1 '05 #18
KJ
Hmm. Let me see if I have your concern correct: A user of your class
may forcibly abort threads instantiated and running methods of that
class? Perhaps you might take another tact: simply make the threading
aspects of the class "opaque" to clients of it. This is possible using
a "design pattern" such as Strategy, or Producer/Controller, or
whatever you please. Whether or not this is a .net bug is something I
wouldn't worry much about. You could actually catch the
SynchronizationLockException in the finally block, no?

If possible, don't give clients of your code the opportunity to
suspend/start/stop/abort (etc.) your threads, or lock your classes'
objects. What a client doesn't know can't hurt them. If they call
YourObject.Foo(), and that starts a new thread running the Bar()
method, so be it. The caller doesn't need to know this.

Hope this helps, even if it's not 100% correct in every detail.

Dec 1 '05 #19
Isn't this simply a minor code issue? Avoiding the "this" /
"some-other-object" debate, shouldn't this be:

Monitor.Enter(lockObj);
try {
// do something
}
finally {
Monitor.Exit(lockObj);
}

Done the original way, surely you don't know (in the finally block where you
release the lock) that you have actually taken the lock; with the above code
you know that if you made it to the try block you *have* the lock...

Apologies if this is my naivety showing through and the above is in fact
incorrect...

Marc
"Michael Kennedy" <mk******@unitedbinary.com> wrote in message
news:11*********************@f14g2000cwb.googlegro ups.com...
Hi,

I have been looking into the claim that the keyword lock is not safe
when exceptions are possible. That lead me to try the following code,
which I think has uncovered a serious error in the .NET 2.0 framework.
Note that this runs better, but not perfectly, on .NET 1.1.

Note: The numbers are line numbers needed to match the callstack of the
exception below.

// Class WorkItem ...
34 public void DoItSafeLock()
35 {
36 try
37 {
38 Monitor.Enter(this);
39 Thread.Sleep(10);
40 }
41 finally
42 {
43 Monitor.Exit(this); // <-- SynchronizationLockException!
44 }
45 }

Here's what I get when I run this code on a different thread than the
one that created the object holding this method (WorkItem class):

System.Threading.SynchronizationLockException: Object synchronization
method was called from an unsynchronized block of code.
at WorkItems.WorkItem.DoItSafeLock() in
D:\LockTest\WorkItems\WorkItem.cs:line 43
at WorkItems.Worker.ExecuteWorkItem() in
D:\LockTest\WorkItems\Worker.cs:line 127

Notice that the error is that on line 43, the object does not hold a
lock on itself (this). How is this possible given that it made it
through the Monitor.Enter(this) call on line 38?!?

Does any one know what's going on here? How can the monitor be entered
and yet no lock is acquired?

I have a sample application demonstrating the error if any one wants to
see the code, just email me and I'll zip up the solution and send it
your way.

Thanks in advance,
Michael

Michael Kennedy

Dec 1 '05 #20
When your thread gets aborted after you have obtained the lock but before
you entered the try block, you end with an unreleased lock. The point here
is not the sequence by which things are done, it's simply that you should
not call Abort() on another running thread (called an asynchronous thread
abort).

Willy.
"Marc Gravell" <mg******@rm.com> wrote in message
news:u7**************@tk2msftngp13.phx.gbl...
Isn't this simply a minor code issue? Avoiding the "this" /
"some-other-object" debate, shouldn't this be:

Monitor.Enter(lockObj);
try {
// do something
}
finally {
Monitor.Exit(lockObj);
}

Done the original way, surely you don't know (in the finally block where
you release the lock) that you have actually taken the lock; with the
above code you know that if you made it to the try block you *have* the
lock...

Apologies if this is my naivety showing through and the above is in fact
incorrect...

Marc
"Michael Kennedy" <mk******@unitedbinary.com> wrote in message
news:11*********************@f14g2000cwb.googlegro ups.com...
Hi,

I have been looking into the claim that the keyword lock is not safe
when exceptions are possible. That lead me to try the following code,
which I think has uncovered a serious error in the .NET 2.0 framework.
Note that this runs better, but not perfectly, on .NET 1.1.

Note: The numbers are line numbers needed to match the callstack of the
exception below.

// Class WorkItem ...
34 public void DoItSafeLock()
35 {
36 try
37 {
38 Monitor.Enter(this);
39 Thread.Sleep(10);
40 }
41 finally
42 {
43 Monitor.Exit(this); // <-- SynchronizationLockException!
44 }
45 }

Here's what I get when I run this code on a different thread than the
one that created the object holding this method (WorkItem class):

System.Threading.SynchronizationLockException: Object synchronization
method was called from an unsynchronized block of code.
at WorkItems.WorkItem.DoItSafeLock() in
D:\LockTest\WorkItems\WorkItem.cs:line 43
at WorkItems.Worker.ExecuteWorkItem() in
D:\LockTest\WorkItems\Worker.cs:line 127

Notice that the error is that on line 43, the object does not hold a
lock on itself (this). How is this possible given that it made it
through the Monitor.Enter(this) call on line 38?!?

Does any one know what's going on here? How can the monitor be entered
and yet no lock is acquired?

I have a sample application demonstrating the error if any one wants to
see the code, just email me and I'll zip up the solution and send it
your way.

Thanks in advance,
Michael

Michael Kennedy


Dec 1 '05 #21
Michael Kennedy wrote:
I have been looking into the claim that the keyword lock is not safe
when exceptions are possible. That lead me to try the following code,
which I think has uncovered a serious error in the .NET 2.0 framework.
Note that this runs better, but not perfectly, on .NET 1.1.


Actually, in .NET 1.1 Monitor.Exit is completely broken - the docs
claim it throws SynchronizationLockException if the current thread
doesn't own the lock, but in practice it doesn't.

What you're seeing is a consequence of Monitor.Exit doing the *right*
thing in 2.0, combined with the bad practice of aborting (or
interrupting - that can have the same effect) another thread.

See http://www.pobox.com/~skeet/csharp/threads/abort.shtml for more
information.

Jon

Dec 1 '05 #22
Hi Willy,

I think you've convinced me to stop worrying.

My main concert is just that someone would consume my object in their
thread, then abort their thread and effectively break my threading
logic. But after talking with you guys I've seen basically you're
screwed either way entery/try or try/enter.

So I'll just hope no one does that and they get what they get if they
do. ;)

Thanks,
Michael

Dec 1 '05 #23
Hi Jon,
What you're seeing is a consequence of Monitor.Exit doing the *right*
thing in 2.0, combined with the bad practice of aborting (or
interrupting - that can have the same effect) another thread.


Now that I've thought about this for awhile, I see that tou're right.
Thanks for the info!

Regards,
Michael

Dec 1 '05 #24
Hi KJ,

I am familiar with design patterns, but I don't know of anything I
could do to avoid someone creating their own thread, using my objects
(which may not even use a thread directly), aborting their thread, and
breaking my usage of lock().

See my response to Willy for a little more on that:

http://groups.google.com/group/micro...1decd659226df1

Thanks for the help!
Michael

Dec 1 '05 #25
Hi Marc,

Yeah, that part isn't really the issue (this vs lockObj). As Willy has
convinced me, you're basically helpless to keep things working right
once you go down the path to Thread.Abort(). try/enter/... or
enter/try/... either way results in unbalanced enter/exit calls.

Thanks!
Michael

Dec 1 '05 #26

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

77
by: Jon Skeet [C# MVP] | last post by:
Please excuse the cross-post - I'm pretty sure I've had interest in the article on all the groups this is posted to. I've finally managed to finish my article on multi-threading - at least for...
1
by: Peter Schmitz | last post by:
Hi, I just tried to convert my current project to the new beta 2 of the .net framework and I encountered some problems with my thread synchronization - that formerly worked well. When I...
21
by: Illumineo | last post by:
My application uses multiple-threads and is a kind of AI simulation or ALife. This works fine but I was wondering if and how one can make use of hyper-threading in C#? Thanks for any hint,...
15
by: aikwee | last post by:
hi all, i have a software written in vb.net which has many thread in it. The software basically use about 8 threads to monitor in coming data from serial port, and some other thread that...
4
by: Bob | last post by:
- For cleanup, is it sufficient to set a Thread to Nothing after it's done? - It is OK to pass objects out of the thread? (dumb question maybe but I want to be sure) - What's the best way to...
8
by: Michael Kennedy | last post by:
Hi, I have been looking into the claim that the keyword lock is not safe when exceptions are possible. That lead me to try the following code, which I think has uncovered a serious error in the...
1
by: abhra.haldar | last post by:
Hi: I am new to multithreaded applications, and was having some problems coordinating a few threads. Here is the code I use: >>>> ContextStorage cs = new...
2
by: WXS | last post by:
When I see things in .NET 2.0 like obsoletion of suspend/resume because of the public reason MS gives of they think people are using them inappropriately.. use mutex, monitor and other...
126
by: Dann Corbit | last post by:
Rather than create a new way of doing things: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html why not just pick up ACE into the existing standard:...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.