C# version of java's synchronized keyword?
Asked Answered
P

5

354

Does c# have its own version of the java "synchronized" keyword?

I.e. in java it can be specified either to a function, an object or a block of code, like so:

public synchronized void doImportantStuff() {
   // dangerous code goes here.
}

or

public void doImportantStuff() {
   // trivial stuff

   synchronized(someLock) {
      // dangerous code goes here.
   }
}
Pedant answered 12/2, 2009 at 13:23 Comment(3)
The block form requires a reference to lock. In the method form the lock object is implicitly this (or the Class [this.class, not getClass()] for static methods, but don't lock on Classes).Barge
Still not protected ? I always come here because I can't remember that [MethodImpl(MethodImplOptions.Synchronized)] line.Prattle
I think your 2nd snippet wouldn't compile - it needs to synchronized on something.Acetic
W
526

First - most classes will never need to be thread-safe. Use YAGNI: only apply thread-safety when you know you actually are going to use it (and test it).

For the method-level stuff, there is [MethodImpl]:

[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}

This can also be used on accessors (properties and events):

private int i;
public int SomeProperty
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    get { return i; }
    [MethodImpl(MethodImplOptions.Synchronized)]
    set { i = value; }
}

Note that field-like events are synchronized by default, while auto-implemented properties are not:

public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized

Personally, I don't like the implementation of MethodImpl as it locks this or typeof(Foo) - which is against best practice. The preferred option is to use your own locks:

private readonly object syncLock = new object();
public void SomeMethod() {
    lock(syncLock) { /* code */ }
}

Note that for field-like events, the locking implementation is dependent on the compiler; in older Microsoft compilers it is a lock(this) / lock(Type) - however, in more recent compilers it uses Interlocked updates - so thread-safe without the nasty parts.

This allows more granular usage, and allows use of Monitor.Wait/Monitor.Pulse etc to communicate between threads.

A related blog entry (later revisited).

Workhouse answered 12/2, 2009 at 14:0 Comment(19)
@earcam and your question is? That statement is true. The vast majority of classes have no requirement to be thread-safe, will not be tested for thread-safety, and having thread-safety will impact performance. The number of types that genuinely need to worry about threads is very small - intentionally synchronized collections, multiplexers, etc.Workhouse
Sorry @Marc, I deleted the comment shortly afterwards (as without explanation it served no purpose but to smell like a troll). I'll repeat here: ""most classes will never need to be thread-safe" eh?" The reason for my "eh?" is that's quite a sweeping statement. I still disagree but perhaps it's just the way you stated it - in my mind you should always be aware of the context your classes will be used in (frameworks etc). Quite agree the number is small, but here critical. Diff design can remove locks completely; immutable classes and guarding shared state through sync'd collections etc.Halliehallman
@Halliehallman indeed I'm very familiar with deeply threaded code... but that is the exception, not the norm - and even then, not all classes involved need to get involvedWorkhouse
I think I should have simply stated; "most classes will never need to be thread-safe" but "all developers must concurrency aware". In retrospect I agree the number is very small (and definitely something you want to get right once in one place, allowing the majority of classes to interact oblivious to their multi-threaded surroundings). Wish I'd deleted the comment quicker =)Halliehallman
Marc's linked blog post has a March 2010 follow-up saying that in .NET 4.0, MethodImpl and field-like events now generate good synchronization code, and it is no longer necessary to use your own locks.Bridgid
A good majority of applications these days are web-based, served with frameworks relying on heavy instance reuse and complex object lifecycle via dependency-injection. The default mindset these days tends to err to the side of thread-safety.Haya
Note that MSDN recommends against usage of MethodImplOptions.Synchronized : Locking on the instance or on the type, as with the Synchronized flag, is not recommended for public types, because code other than your own can take locks on public types and instances. This might cause deadlocks or other synchronization problems.Amby
@MarcGravell consider re-arranging your answer to highlight best practice and possibly add property sample too (see #33685465 for example of confusion with recommendation).Amby
@AlexeiLevenkov synchronization is so contextual that it is exceptionally hard to give a generic "best practice"...Workhouse
@MarcGravell I would not put one that is least likely to be used correctly to be first in the post, but that is your call. (Comment will self-destruct sometime soon).Amby
Another verbose C# implementation.Secondguess
I get 'MethodImplOptions' does not contain a definition for 'Synchronized'.Garratt
@Garratt any chance you're targeting an exotic framework? Unity, mono, net standard, etc? It definitely exists in .NET : msdn.microsoft.com/en-us/library/…Workhouse
You are right, I've installed some minimal version of VS. But how do I know which components to add?Garratt
@Garratt it doesn't matter what version of VS you're using. What matters is what framework you are targeting.Workhouse
@MarcGravell well the target framework is .NETCoreApp 1.1, but I have no other choices.Garratt
I wasn't able to change the target framework cleanly, so I had to create a new project - now .NET Framework instead of .NETCore.Garratt
@Garratt too late now, but for the record: changing the framework is a one-line change to they csproj if you've created it using the .net standard / .net core templates - and regular .net is available, as is multi-targeting. However, the IDE tooling around this is simply terrible - you just need to know what you can change and to what :)Workhouse
Thanks. I've tried some one-line change I've found in another answer and it rendered the project unreadable (probably related to NuGet) so I assume it was the wrong one :)Garratt
P
68
static object Lock = new object();

lock (Lock) 
{
// do stuff
}
Polyphonic answered 12/2, 2009 at 13:27 Comment(6)
Are you sure you want to declare your lock object as static..?Ejective
Sure, so every Thread can easily access it without passing references around.Polyphonic
If we are in the context of the asker's question, then we are talking about instance methods. Using static means that if thread 1 calls instance1.DoSomething() and thread 2 calls instance2.DoSomething, the second call will block even though it is a completely different object. thread2's call shouldn't block unless someone is calling DoSomething on the same object. Not saying you are wrong, but saying it is important to understand the effect of using static here, because it may cause poor performance by blocking globally instead of on a per instance basis.Human
@Human The static lock if very useful when your object performs actions on a bigger scope than itself. Always happens with web-services for example.Bran
-1 as this is a different behavior than the OP is asking for. This is a class lock, not an instance lock.Kevakevan
with static: Assume some odd-thread you never thought about access this static Lock object for some other locking purpose - mean not on this code block. Then Lock is acquired by this odd-thread. Now comes your thread pool and they are going to access your code block, but non of them can't go inside because the odd-thread hasn't released the Lock object yet. I think this is very exceptional case which you want to go with by knowing the impact. Do not use static locks as a common practice if you go with instance methods. I'm from Java, but concept should be same I guess :)Sangfroid
B
39

Does c# have its own version of the java "synchronized" keyword?

No. In C#, you explicitly lock resources that you want to work on synchronously across asynchronous threads. lock opens a block; it doesn't work on method level.

However, the underlying mechanism is similar since lock works by invoking Monitor.Enter (and subsequently Monitor.Exit) on the runtime. Java works the same way, according to the Sun documentation.

Blinker answered 12/2, 2009 at 13:24 Comment(3)
It doesn't have an equivalent "keyword", but as Marc Gravell's answer above shows, you can synchronize at the method level using the [MethodImpl(MethodImplOptions.Synchronized)] annotation.Eulogize
Since Java's synchronized on method is basically synchronized (this.getClass()) wouldn't the similar on C# be lock(typeof(this))?Centigram
@SriHarshaChilakapati that's only partially correct, java's synchronized keyword on a method is more like: synchronized(this) , only on a static method it behaves like synchronized(class).Chukchi
E
6

Take note, with full paths the line: [MethodImpl(MethodImplOptions.Synchronized)] should look like

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]

Extra answered 24/7, 2013 at 13:32 Comment(3)
or you can just use using System.Runtime.CompilerServices;Seraphim
I wrote that comment when I didn't yet know about automatically inserting using statements, after having programmed C# for no more than a few days or weeks and I am amazed about those 3 upvotes.Extra
You helped at least 3 devs and that's nice :)Seraphim
A
5

You can use the lock statement instead. I think this can only replace the second version. Also, remember that both synchronized and lock need to operate on an object.

Aggri answered 12/2, 2009 at 13:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.