473,573 Members | 2,842 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Don't Lock Type Objects!

http://msdn.microsoft.com/library/de...ui06032003.asp

Don't Lock Type Objects!

Why Lock(typeof(Cla ssName)) or SyncLock GetType(ClassNa me) Is Bad
Rico Mariani, performance architect for the Microsoft® .NET runtime
and longtime Microsoft developer, mentioned to Dr. GUI in an e-mail
conversation recently that a fairly common practice (and one that's,
unfortunately, described in some of our documentation right now,
although we'll be fixing that) is actually quite problematic. He asked
if Dr. GUI could help get the word out that programmers shouldn't do
this. The good doctor was delighted to oblige.

What is this fairly common practice? Well, it's getting a lock on a
type object. In C#, it's lock(typeof(Cla ssName)) where ClassName is
the name of some class; in Microsoft® Visual Basic® .NET, it's
SyncLock GetType(ClassNa me).

A bit of background: The lock/SyncLock statement is used in
multithreaded programming to create critical sections, or brief
sections of your code where only one thread can execute at a time.
(You might need this if you had to update more than one field in your
object simultaneously— you'd want to make sure that another thread
didn't try to update the object at the same time!) This statement
locks the unique monitor object associated with the object you
specify, waiting if another thread has the monitor already. Once it
locks the monitor, no other thread can lock it until your thread
releases the lock, which happens automatically at the end of enclosed
block. A common usage is to lock the this/Me reference so that only
your thread can modify the object you're using—or better yet, to lock
the specific object you're about to modify. Locking the smallest
possible object is good because it helps to avoid needless waiting.

GetType and typeof return a reference to the type object for that
type. The type object, of type System.Type, contains methods that
allow you to reflect on the type, meaning you can find its fields and
methods, and even access fields and call methods. You can even create
an instance of the object once you have a reference to the type object
(and you can get a reference to a type object by name if you use the
Type.GetType shared/static method).

So the type object is pretty handy. But some programmers have taken to
using it as a "cheap" way of getting a proxy for a static/Shared
object you can put a lock on. (And, unfortunately, we document this in
both the C# and Visual Basic .NET documentation, implying that it's a
recommended practice.) In this case, the docs are wrong (and we'll be
correcting them). This practice is not acceptable, let alone
recommended.

Here's why: Since there's one type object for all instances of a
class, it would appear that locking it would provide a lock equivalent
to locking a static object contained in your class. You would lock all
instances of the class, wait until other threads were done accessing
any part of any instance, then lock access so you could access static
members safely and without another thread interfering.

And it does work, at least most of the time. But there are problems
with it: First, getting the type object is actually a fairly slow
process (although most programmers would guess that it's extremely
fast); second, other threads in ANY CLASS and even different programs
running in the same application domain have access to the type object,
so it's possible that they'll lock the type object on you, blocking
your execution entirely and causing you to hang.

The basic problem here is that you don't own the type object, and you
don't know who else could access it. In general, it's a very bad idea
to rely on locking an object you didn't create and don't know who else
might be accessing. Doing so invites deadlock. The safest way is to
only lock private objects.

But wait; it's even worse than all that. As it turns out, type objects
are sometimes shared across application domains (but not across
processes) in current versions of the .NET runtime. (This is generally
okay since they're immutable.) That means that it's possible for
ANOTHER APPLICATION running even in a different application domain
(but in the same process) to deadlock your application by getting a
lock on a type object you want to lock and never releasing it. And it
would be easy to get access to that type object because the object has
a name—the fully qualified name of the type! Remember that
lock/SyncLock blocks (that's a polite word for hangs) until it can
obtain a lock. It's obviously really quite bad to rely on a lock that
another program or component can lock and cause you to deadlock.

Even if the type objects were unique to your application domain, this
would still be a bad practice because any code could get access to the
type object for a public type and cause a deadlock. This is especially
a problem when you use components in your application that you didn't
write. (Even lock(this)/SyncLock Me can have this problem, since
someone else can lock you. Although if that happens, it's likely to be
easier to find than the deadlock caused by locking a type object,
since your object isn't globally available across application
domains.)

So what should you do instead? Well, it's pretty easy: just declare
and create an object to use as a lock, then use it, not the type
object, to do your locking. Usually, to duplicate the intended
semantics of the bad code, you'll want this object to be
static/Shared—and it really, of course, should be private! In general,
you could change the following bad code:

// C#
lock(typeof(Foo )) { // BAD CODE! NO! NO! NO!
// statements;
}

' VB .NET
SyncLock GetType(MyClass ) ' BAD CODE! NO! NO! NO!
' statements
End SyncLock

…into the following good code:

// C#
lock(somePrivat eStaticObject) { // Good code!
// statements;
}

' VB .NET
SyncLock GetType(somePri vateStaticObjec t) ' Good code!
' statements
End SyncLock

Of course, you'll have to either have a private static object to lock
already (if you're using the lock to modify static objects, you may in
fact already have one!) or you'll have to create one. (Make it private
to keep other classes from locking your object.) Do NOT attempt to
lock a field that's not a reference (object) type, such as
int/Integer. You'll get a compiler error. If you don't have a private
static object to lock, you may need to create a dummy object:

// C#
Class MyClass {
private static Object somePrivateStat icObject = new Object();
// methods of class go here--can lock somePrivateStat icObject
}

' VB .NET
Class MyClass
Private Shared somePrivateStat icObject As New Object
' methods of class go here--can lock somePrivateStat icObject
End Class

You'll want to analyze each case separately to make sure you've got it
right, but in general, the above technique should work.

Note a couple of things: First, no code outside of your class can lock
MyClass.somePri vateStaticObjec t, so you've eliminated many
opportunities for deadlock. And deadlocks are among the nastiest bugs
to find, so eliminating opportunities for them is a very good thing.

Second, you know that there's exactly one copy of
MyClass.somePri vateStaticObjec t for your application and exactly one
for each other application on the system that is running, so there's
no interplay across applications in the same application domain. Dr.
GUI hopes you can see why this code is much more reliable and robust
than the bad code.

To summarize, don't lock type objects. You don't know where they've
been. Doing so is slow and can expose you to possible deadlock
situations. It's a bad programming practice. Instead, lock a static
object in your object.
Nov 16 '05 #1
0 17755

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

Similar topics

2
1727
by: Fuzzyman | last post by:
Looking at threading code it seems that the Global Interpreter Lock is a bit of a 'brute force' way of preventing two threads attempting to access sensitive objects simultaneously.... Why not have a new type of object with a 'lock' facility... if an object is locked then any thread trying to access the object other than the one obtaining...
7
703
by: Sunny | last post by:
Hi, I can not understend completely the lock statement. Actally what is locked: 1. the part of the code between {...} or 2. the object in lock() In the docs is written: for 1: The lock keyword marks a statement block as a critical section by obtaining the mutual-exclusion lock for a given object, executing a
3
2658
by: Invalid | last post by:
I launch a worker thread that periodically reads a volatile bool abortRequested, which could be set to true by my main form. IOW, there is one thread that can read that bool and one different thread that can set it. See code below for an overview. In a C or C++ environment, my current approach would be adequate (no need to acquire...
4
1962
by: Jeff Stewart | last post by:
Specifically, I don't understand the parameter that Synclock accepts. How is a reference type a lockable entity? What -is- a reference type? Is it a number? Is it a value at a specific memory location? Does synclocking a reference type put an entry in a catalog somewhere in the system, and it's removed on the "end synclock" statement? ...
3
6620
by: Raj | last post by:
I created a refresh deferred MQT, and during full refresh there were 4 or 5 lock waits, all waiting on a 'S' lock on Internal Catalog Cache ? Can some one explain how to prevent this from happening?
2
2618
by: WingSiu | last post by:
I am writing a Logging util for my ASP.NET application. I am facing mulit process problem. I developed a class LogFactory, and have a method called Get_Logger to create a FileLogger, which will write text into a text file. // sample code FileLogger logger = LogFactory.Get_Logger(); logger.Log("Message here");
11
7967
by: fritzcwdev | last post by:
I have a class as follows: public class OperationFeedback { DateTime _startTime; public DateTime StartTime { get {
6
7703
by: michael.spoden | last post by:
Hi, how can I fix lock-waits during an online backup? Is an online backup in DB2 V8.2 not realy online? I'm using DB2 V8.2 Fixpak 15 on Linux. The command to perform the backup is: db2 backup db BPEDB online to / var/tmp During the backup the application hangs on just one table
6
1903
by: Curious | last post by:
I have an arraylist used in three separate methods. In method #1 (event method), some items are removed from the arraylist if certain conditions are met; In method #2 (event method), properties of some items are modified if certain conditions are met; In method #3, it loops through each item in the arraylist without changing any item...
0
7755
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7679
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7992
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
6385
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5571
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
5281
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3722
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
3722
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
1284
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.