350

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.
   }
}
Soraz
  • 6,610
  • 4
  • 31
  • 48
  • 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). – Tom Hawtin - tackline Feb 12 '09 at 13:45
  • 3
    Still not protected ? I always come here because I can't remember that `[MethodImpl(MethodImplOptions.Synchronized)]` line. – Bitterblue Mar 17 '14 at 13:00
  • 1
    I think your 2nd snippet wouldn't compile - it needs to *synchronized* on something. – PoweredByRice Oct 16 '15 at 21:48

5 Answers5

517

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).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • @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. – Marc Gravell Nov 08 '11 at 09:02
  • 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. – earcam Nov 08 '11 at 10:17
  • @earcam 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 involved – Marc Gravell Nov 08 '11 at 10:21
  • 6
    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 =) – earcam Nov 08 '11 at 10:34
  • 8
    Marc's [linked blog post](http://marcgravell.blogspot.com/2009/02/fun-with-field-like-events.html) has a [March 2010 follow-up](http://marcgravell.blogspot.com/2010/03/revisited-fun-with-field-like-events.html) 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. – Rory O'Kane Jun 03 '13 at 19:47
  • 2
    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. – Sheepy Jan 10 '15 at 07:11
  • Note that MSDN recommends *against* usage of [MethodImplOptions.Synchronized](https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions(v=vs.110).aspx) : 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. – Alexei Levenkov Nov 13 '15 at 04:27
  • @MarcGravell consider re-arranging your answer to highlight best practice and possibly add property sample too (see http://stackoverflow.com/questions/33684965/what-is-a-thread-safe-way-to-read-write-a-c-sharp-property-in-a-class for example of confusion with recommendation). – Alexei Levenkov Nov 13 '15 at 04:31
  • @AlexeiLevenkov synchronization is so contextual that it is exceptionally hard to give a generic "best practice"... – Marc Gravell Nov 13 '15 at 08:00
  • @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). – Alexei Levenkov Nov 13 '15 at 17:11
  • Another verbose C# implementation. – Oliver Dixon Jun 26 '16 at 14:45
  • I get `'MethodImplOptions' does not contain a definition for 'Synchronized'`. – Elazar Aug 13 '17 at 09:49
  • @Elazar any chance you're targeting an exotic framework? Unity, mono, net standard, etc? It definitely exists in .NET : https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions(v=vs.110).aspx – Marc Gravell Aug 13 '17 at 19:40
  • You are right, I've installed some minimal version of VS. But how do I know which components to add? – Elazar Aug 14 '17 at 12:35
  • @Elazar it doesn't matter what version of VS you're using. What matters is what framework you are targeting. – Marc Gravell Aug 14 '17 at 12:48
  • @MarcGravell well the target framework is `.NETCoreApp 1.1`, but I have no other choices. – Elazar Aug 14 '17 at 14:49
  • I wasn't able to change the target framework cleanly, so I had to create a new project - now `.NET Framework` instead of `.NETCore`. – Elazar Aug 15 '17 at 21:33
  • 1
    @Elazar 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 :) – Marc Gravell Aug 15 '17 at 22:35
  • 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 :) – Elazar Aug 16 '17 at 06:24
68
static object Lock = new object();

lock (Lock) 
{
// do stuff
}
Jan Gressmann
  • 5,481
  • 4
  • 32
  • 26
  • 13
    Are you sure you want to declare your lock object as static..? – serg10 Feb 12 '09 at 20:13
  • 22
    Sure, so every Thread can easily access it without passing references around. – Jan Gressmann Feb 12 '09 at 21:27
  • 40
    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. – AaronLS Apr 15 '13 at 07:03
  • 1
    @AaronLS The static lock if very useful when your object performs actions on a bigger scope than itself. Always happens with web-services for example. – Thibault D. Apr 19 '13 at 12:59
  • 7
    -1 as this is a different behavior than the OP is asking for. This is a class lock, not an instance lock. – tster Oct 25 '13 at 18:51
  • 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 :) – sura2k Mar 23 '18 at 17:46
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.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 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. – MindJuice Jan 03 '13 at 19:28
  • 1
    Since Java's `synchronized` on method is basically `synchronized (this.getClass())` wouldn't the similar on C# be `lock(typeof(this))`? – Sri Harsha Chilakapati Apr 01 '17 at 18:56
  • 2
    @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)`. – bvdb Jul 03 '18 at 12:07
6

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

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

4444
  • 3,541
  • 10
  • 32
  • 43
ASA
  • 1,911
  • 3
  • 20
  • 37
  • 3
    or you can just use `using System.Runtime.CompilerServices;` – aloisdg Sep 11 '15 at 13:27
  • 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. – ASA Sep 11 '15 at 22:47
  • 1
    You helped at least 3 devs and that's nice :) – aloisdg Sep 11 '15 at 23:01
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.

James
  • 2,050
  • 13
  • 15