How expensive is the lock instruction?

I experimented with multi-threaded and parallel processing, and I need a counter to perform basic counting and statistical analysis of processing speed. To avoid problems while using my class at the same time, I used the lock statement for a private variable in my class:

private object mutex = new object(); public void Count(int amount) { lock(mutex) { done += amount; } } 

But I was wondering ... how expensive is locking a variable? What are the negative performance implications?

+72
multithreading c # parallel-processing locking
Jan 12 '11 at 20:20
source share
7 answers

Here is an article that is included in the price. The short answer is 50 ns.

+61
Jan 12 '11 at 20:22
source share

The technical answer is that it cannot be quantified; it largely depends on the state of the writeback buffers of the processor memory and the amount of data that the collector collected should be discarded and re-read. Which are very non-deterministic. I use 150 CPU cycles as an approximation to the back shell, which avoids serious disappointments.

The practical answer: this is waaaay cheaper than the amount of time you will write when debugging your code when you think you might skip the lock.

To get a hard number, you have to measure. Visual Studio has a sleek concurrency analyzer available as an extension.

+41
Jan 12 2018-11-11T00:
source share

Oh my God!

It seems that the correct answer is marked here as ANSWER, which is essentially incorrect! I would like to ask the author of the answer, with respect, to read the related article to the end. article

The author of the article from the article was evaluated only on a dual-core processor, and in the first measurement case he measured the lock with only one thread and the result was about 50 ns for access to the lock.

It says nothing about locking in a parallel environment. Thus, we should continue reading the article, and in the second half, the author measured a blocking scenario with two and three threads, which approaches the levels of modern concurrency processors.

So, the author says that with two threads on Dual Core locks cost 120 ns, and with 3 threads it goes to 180 ns. Thus, it clearly depends on the number of simultaneously available threads, and even worse.

So, itโ€™s simple, itโ€™s not 50 ns, unless it is a single thread where the lock becomes useless.

Another issue to consider is that it is measured as average time !

If iteration time were measured, there would even be a time between 1 ms to 20 ms, simply because most were fast, but several threads were waiting for processor time and even had millisecond delays.

This is bad news for any application that requires high bandwidth, low latency.

And the last question to consider is that inside the lock there may be slower operations, and this is often the case. The longer the code block runs inside the castle, the higher the conflict and the increase in the height of the sky is delayed.

Please think that more than one decade has already passed since 2003, that is, several generations of processors designed specifically for simultaneous start and blocking significantly degrade their performance.

+22
Sep 27 '15 at 6:21
source share

This does not answer your request for performance, but I can say that the .NET Framework offers the Interlocked.Add method, which allows you to add your amount to your done element without manually locking another object.

+17
Jan 12 '11 at 20:23
source share

lock (Monitor.Enter / Exit) is very cheap, cheaper than alternatives like Waithandle or Mutex.

But what if it was (a bit) slow, would you rather suggest a quick program with incorrect results?

+9
Jan 12 '11 at 20:25
source share

The cost of locking in a tight loop is huge compared to the alternative without locking. You can allow yourself a loop many times and still be more efficient than locking. This is why blocking free queues is so effective.

 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace LockPerformanceConsoleApplication { class Program { static void Main(string[] args) { var stopwatch = new Stopwatch(); const int LoopCount = (int) (100 * 1e6); int counter = 0; for (int repetition = 0; repetition < 5; repetition++) { stopwatch.Reset(); stopwatch.Start(); for (int i = 0; i < LoopCount; i++) lock (stopwatch) counter = i; stopwatch.Stop(); Console.WriteLine("With lock: {0}", stopwatch.ElapsedMilliseconds); stopwatch.Reset(); stopwatch.Start(); for (int i = 0; i < LoopCount; i++) counter = i; stopwatch.Stop(); Console.WriteLine("Without lock: {0}", stopwatch.ElapsedMilliseconds); } Console.ReadKey(); } } } 

Output:

 With lock: 2013 Without lock: 211 With lock: 2002 Without lock: 210 With lock: 1989 Without lock: 210 With lock: 1987 Without lock: 207 With lock: 1988 Without lock: 208 
+6
Sep 29 '13 at 19:16
source share

There are several different ways to define "value." Actual overhead costs of receiving and releasing the lock; as Jake writes, this is insignificant if this operation is not performed millions of times.

More relevant is the effect of this on the progress. This code can only be entered one thread at a time. If you have 5 threads performing this operation on a regular basis, 4 of them ultimately expect the lock to be released, and then to be the first thread scheduled to enter this piece of code after the lock is released. Thus, your algorithm will suffer greatly. How much this depends on the algorithm and how often the operation is called. You cannot avoid this without entering race conditions, but you can improve it by minimizing the number of calls to the blocked code.

+4
Jan 12 '11 at 20:33
source share



All Articles