Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why lock(<integer var>) is not allowed, but Monitor.Enter(<integer var>) allowed?

For the following code I get a compile time error, *

'int' is not a reference type as required by the lock statement

int i = 0;
lock(i);

But no errors for this:

int i = 0;
Monitor.Enter(i);

I understand that a value type shouldn't be used for locking due to the complications arising due to boxing. But, then why does it work with Monitor.

like image 780
Sandbox Avatar asked Aug 25 '09 17:08

Sandbox


People also ask

Can you lock a value type?

Remember that when you pass a value type for a parameter of type object , it gets boxed (wrapped) into a reference type. This makes it a brand-new object each time this happens. You cannot lock a value type because it doesn't have a sync root record.

What is the difference between lock and monitor in C#?

CSharp Online Training Both Monitor and lock provides a mechanism that synchronizes access to objects. lock is the shortcut for Monitor. Enter with try and finally. Lock is a shortcut and it's the option for the basic usage.

Why should you avoid the lock keyword?

Avoid using 'lock keyword' on string object String object: Avoid using lock statements on string objects, because the interned strings are essentially global in nature and may be blocked by other threads without your knowledge, which can cause a deadlock.

Does a lock block thread?

Lock is not blocking threads. It is locking some instance of an object. And each thread which tries to access it is blocked.


3 Answers

The reason why is that lock is a language construct and compiler chooses to impose extra semantics on the expression. Monitor.Enter is simply a method call and the C# compiler does not special case the call in any way and hence it goes through normal overload resolution and boxing.

like image 127
JaredPar Avatar answered Nov 10 '22 07:11

JaredPar


You should definitely not use Monitor.Enter on an int. The reason it works is because the int is boxed, so unless you store a reference to the boxed value, you will be locking on a temporary object, which means that you cannot call Monitor.Exit without getting an exception.

The recommended way to do locking is to create a private readonly object and lock on that. For a static method you can use a private static object.

like image 31
Brian Rasmussen Avatar answered Nov 10 '22 06:11

Brian Rasmussen


The specification for the compiler defines the behaviour of lock like so:

The compile time type of the expression of a lock statement shall be a reference-type or a > type parameter (§25.1.1) known to be a reference type. It is a compile-time error for the compile time type of the expression to denote a value-type.

It then defines what it is equivalent to so long as it compiles

Since Monitor.Exit is just a method call without any constraints it will not prevent the compiler automatically boxing the int and going on its merry (and very) wrong way.

lock is NOT simply syntactic sugar in the same way foreach is not simply syntactic sugar. The resulting IL transform is not presented to the rest of the code as if that was what had been written.

In foreach it is illegal to modify the iteration variable (despite there being nothing at the IL level in the resulting output code that would prevent this). In lock the compiler prevents compile time known value types, again despite the resulting IL not caring about this.

As an aside:
In theory the compiler could be 'blessed' with intimate knowledge of this (and other) methods so that it spotted obvious cases of this happening but fundamentally it is impossible to always spot this at compile time (consider an object passed in from another method, assembly or via reflection) so bothering to spot any such instances would likely be counter productive.

The more the compiler knows about the internals of the API the more problems you will have if you wish to alter the API in future.

It is possible for example that an overload of Monitor.Enter() could be added which took an int and locked on a process wide mutex associated with the int value.
This would conform to the specifications of monitor (even though it would likely be hideous) but would cause massive problems for the older compiler still merrily preventing an operation which had become legal.

like image 20
ShuggyCoUk Avatar answered Nov 10 '22 08:11

ShuggyCoUk