Is it possible to mix a mixing class with a lock ()?

Is atomic read guaranteed when you mix lock operations with lock () (and other higher-level locks)?

I am interested in the general behavior when mixing locking mechanisms like this and any differences between Int32 and Int64.

private Int64 count; private object _myLock; public Int64 Count { get { lock(_myLock) { return count; } } } public void Increment { Interlocked.Increment(ref count); } 
+7
multithreading c #
source share
5 answers

Note. This answer (including two changes already) was given before the question was changed to have a long count . For the current question, instead of Thread.VolatileRead I would use Interlocked.Read , which also had volatile semantics, and also examined the 64-bit reading problem described here and introduced into the question

Atomic reading is guaranteed without blocking, since reading correctly aligned values ​​of 32-bit or less, which is your count , is guaranteed to be atomic.

This is different from a 64-bit value, if it started with -1 and was read while another thread was increasing it, it could cause the value to be -1 (happened before the increment), 0 (happened after the increment) or any of 4294967295 or -4294967296 (32 bits written to 0, other 32 bits waiting to be written).

Atomic increment Interlocked.Increment means that the entire increment operation is atomic. Consider the increment conceptually:

  • Read the meaning.
  • Add a value to the value.
  • Enter value.

Then, if x is 54, and one thread tries to increase it, and the other tries to set it to 67, two correct possible values ​​are 67 (increment occurs first, then is written) or 68 (assignment happens first, then increases), but the non-atomic increment can lead to 55 (reading increment, assignment 67 occurs, increment writes).

A more general real case: x is 54, and one thread increases and the other decreases. Here the only real result is 54 (one up, then one down or vice versa), but if not atomic, then results 53, 54 and 55 are possible.

If you just want the number that was incremented using atomic input to have the correct code:

 private int count; public int Count { get { return Thread.VolatileRead(byref count); } } public void Increment { Interlocked.Increment(count); } 

If you want to act on this account, then a stronger lock will be required. This is due to the fact that the thread using the account may become outdated before its completion. In this case, you need to fix everything that worries the account and everything that changes it. Just how it needs to be done (and whether it is important to do it at all) depends on more questions from your use case than can be deduced from your question.

Edit: Oh, you can just lock to force a memory barrier. You can also change the implementation of count to return Thread.VolatileRead(ref count); to ensure that the processor caches are cleared if you intend to remove the lock. It depends on how important the importance of the cache is in this case. (Another alternative is to make count volatile, since then all reads and writes will be volatile. Note that this is not required for Interlocked operations, as they are always unstable.)

Edit 2: In fact, you probably want this mutable read that I am changing the answer above. it you may not care what he offers, but much less likely.

+9
source share

The argument provided to the lock keyword must be an object based on a reference type. In your code, this is the type of value; it probably means boxing, which makes commit useless.

A lock operation is atomic with respect to another lock operation performed on another thread and applies to the same variable. Thread safety does not exist if one thread uses the lock operation and the other modifies the same variable using a different synchronization algorithm or without synchronization.

+3
source share

Is atomic read guaranteed when you mix lock operations with lock () (and other higher-level locks)?

The atomic read int is always guaranteed regardless of any type of lock. The C # specification states that reading ints is always atomic.

I think your real question is different from the one you asked. Can you clarify the question?

+3
source share

The answer to your question is no. lock and Interlocked have nothing to do with each other, and they do not work together as you suggest.

Also, not sure what is going on with your code. It does not compile. You cannot block the value type. In addition, Increment() takes a ref argument.

+2
source share

First, you cannot block value types, for example, int.

When you lock a value type, it is first placed in the object. The problem is that it will be placed in the box every time, and each time it will be a different "box". Each time you will block another object, making the blocking block useless.

In this situation, let's say you block the reference type and you use the Interlocked class in another thread. There will be no synchronization between threads. If you need synchronization, you should use the same mechanism for both threads.

+2
source share

All Articles