Does [MethodImpl(MethodImplOptions.Synchronized)] lock the entire object?

S

Seeker

Hello,

I've read conflicting posts about
[MethodImpl(MethodImplOptions.Synchronized)]. Does it or does it not lock
the entire object? In my simple test it appears to block just the method but
I wouldn't exactly call my meager test conclusive...

thanks,
Scott
 
J

Jon Skeet [C# MVP]

Seeker said:
I've read conflicting posts about
[MethodImpl(MethodImplOptions.Synchronized)]. Does it or does it not lock
the entire object? In my simple test it appears to block just the method but
I wouldn't exactly call my meager test conclusive...

It's the equivalent to putting lock(this) round the whole method call.
Here's some code to indicate that:

using System;
using System.Runtime.CompilerServices;
using System.Threading;

class Test
{
static void Main()
{
new Test().Run();
}

[MethodImpl(MethodImplOptions.Synchronized)]
void Run()
{
Monitor.Pulse(this);
}
}

Compile and run it - it's fine. Comment out the attribute and it fails
though, because the thread doesn't own the monitor for "this" without
the attribute.

I wouldn't suggest using the attribute though - I'd use an explicit
lock. I also wouldn't lock on "this" - see
http://www.pobox.com/~skeet/csharp/threads/lockchoice.shtml
 
S

Seeker

Nice link, Thanks!

Still toying around with my joke of a test program and I think I discovered
another interesting side effect of this attribute. It seems to not only lock
the current method but also any other methods marked with this attribute in
the object.

MethodA() manipulates dataX
MethodB() manipulates dataX
MethodC() manipulates dataY

Each method has the [MethodImpl(MethodImplOptions.Synchronized)] attribute.
And I start 3 threads (one thread calls MethodA etc). I found that the order
is Thread1, Thread2 then Thread3. So it looks like Thread1 put a lock on all
three methods. If I remove the attribute from Method3 then the order changes
to Thread3, Thread1, Thread2. If I remove all the attributes the order
varies and I can get errors (trying to remove some data that doesn't exist
yet).



I'm starting to understand why this isn't a good thing. I think we are
better off with a more granular locking mechanism using the lock().

Scott

Jon Skeet said:
Seeker said:
I've read conflicting posts about
[MethodImpl(MethodImplOptions.Synchronized)]. Does it or does it not lock
the entire object? In my simple test it appears to block just the method but
I wouldn't exactly call my meager test conclusive...

It's the equivalent to putting lock(this) round the whole method call.
Here's some code to indicate that:

using System;
using System.Runtime.CompilerServices;
using System.Threading;

class Test
{
static void Main()
{
new Test().Run();
}

[MethodImpl(MethodImplOptions.Synchronized)]
void Run()
{
Monitor.Pulse(this);
}
}

Compile and run it - it's fine. Comment out the attribute and it fails
though, because the thread doesn't own the monitor for "this" without
the attribute.

I wouldn't suggest using the attribute though - I'd use an explicit
lock. I also wouldn't lock on "this" - see
http://www.pobox.com/~skeet/csharp/threads/lockchoice.shtml
 
J

Jon Skeet [C# MVP]

Seeker said:
Nice link, Thanks!

Still toying around with my joke of a test program and I think I discovered
another interesting side effect of this attribute. It seems to not only lock
the current method but also any other methods marked with this attribute in
the object.

Yes, because it's taking out a lock on the "this" reference, which
isn't specific to the method.
MethodA() manipulates dataX
MethodB() manipulates dataX
MethodC() manipulates dataY

Each method has the [MethodImpl(MethodImplOptions.Synchronized)] attribute.
And I start 3 threads (one thread calls MethodA etc). I found that the order
is Thread1, Thread2 then Thread3. So it looks like Thread1 put a lock on all
three methods. If I remove the attribute from Method3 then the order changes
to Thread3, Thread1, Thread2. If I remove all the attributes the order
varies and I can get errors (trying to remove some data that doesn't exist
yet).

You're starting with the wrong concept - the idea of a method being
locked. It's not a method that's locked, it's a reference. In this
case, it's the "this" reference.
I'm starting to understand why this isn't a good thing. I think we are
better off with a more granular locking mechanism using the lock().

Yup - in your case, MethoA and MethodB would use one lock, whereas
MethodC would use another - if you really need that kind of
granularity. (It's often wise to go for a single lock even if it
doesn't give the highest performance, for the sake of memory and ease
of understanding.)

Of course, those methods probably don't need to lock for the *whole*
time they're in the method - just the time that they're manipulating
the shared data.
 
S

Seeker

Ok, just a couple more questions and I really do appreciate your time. When
the attribute is used on some of the methods in an object and you have multi
threads, how is it that a thread is still able to access the non-attribute
methods when there is a lock on "this"? Shouldn't a lock on the object's
reference in effect block all threads and therefore in effect cause the
entire object to lock?

Scott

Jon Skeet said:
Seeker said:
Nice link, Thanks!

Still toying around with my joke of a test program and I think I discovered
another interesting side effect of this attribute. It seems to not only lock
the current method but also any other methods marked with this attribute in
the object.

Yes, because it's taking out a lock on the "this" reference, which
isn't specific to the method.
MethodA() manipulates dataX
MethodB() manipulates dataX
MethodC() manipulates dataY

Each method has the [MethodImpl(MethodImplOptions.Synchronized)] attribute.
And I start 3 threads (one thread calls MethodA etc). I found that the order
is Thread1, Thread2 then Thread3. So it looks like Thread1 put a lock on all
three methods. If I remove the attribute from Method3 then the order changes
to Thread3, Thread1, Thread2. If I remove all the attributes the order
varies and I can get errors (trying to remove some data that doesn't exist
yet).

You're starting with the wrong concept - the idea of a method being
locked. It's not a method that's locked, it's a reference. In this
case, it's the "this" reference.
I'm starting to understand why this isn't a good thing. I think we are
better off with a more granular locking mechanism using the lock().

Yup - in your case, MethoA and MethodB would use one lock, whereas
MethodC would use another - if you really need that kind of
granularity. (It's often wise to go for a single lock even if it
doesn't give the highest performance, for the sake of memory and ease
of understanding.)

Of course, those methods probably don't need to lock for the *whole*
time they're in the method - just the time that they're manipulating
the shared data.
 
J

Jon Skeet [C# MVP]

Seeker said:
Ok, just a couple more questions and I really do appreciate your time. When
the attribute is used on some of the methods in an object and you have multi
threads, how is it that a thread is still able to access the non-attribute
methods when there is a lock on "this"? Shouldn't a lock on the object's
reference in effect block all threads and therefore in effect cause the
entire object to lock?

No - the lock only has an effect if another thread tries to acquire the
lock. If a method isn't marked with the attribute and doesn't contain
any lock statements, no locking occurs.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top