Is ++ operator stream safe?

NOTE. I'm really not very good at multithreaded programming, but in my current project I am doing this, so I'm trying to understand what is thread safe and what is not.

I read one of Eric Lippert's amazing answers to what ++ I am doing . He says this is true:

  • x is computed to create a variable
  • the value of the variable is copied to a temporary location
  • the temporary value is incremented to create a new value (without overwriting the temporary!)
  • the new value is stored in a variable
  • the result of the operation is a new value

This made me think that if there are two threads, where is ++ i being called? If the first thread is in step 3, when the second thread is in step 2. (What does it mean if the second thread copies the value to a temporary location before the first thread stores the new value in the variable?)

If this happens, then it would seem that both threads will only increase i once instead of two. (If all this is not in lock .)

+48
multithreading c #
Jan 07 2018-11-11T00:
source share
3 answers

As the other answers pointed out, no, ++ is not "streaming".

Something that I think will help when you learn about multithreading and its dangers is to start very precisely about what you mean by "threadafe" because different people mean different things. Essentially, the thread safety aspect that bothers you is whether the operation is atomic or not. An β€œatomic” operation is an operation that is guaranteed not to be filled halfway if it is interrupted by another thread.

(There are many other problems with threads that have nothing to do with atomicity, but which may still fall under certain definitions of thread safety. For example, if there are two threads, each of which modifies a variable, and two threads, each of which reads a variable , two readers guarantee agreement on the order in which the other two threads made mutations? If your logic depends on this, then you have a very difficult thread safety problem that can be dealt with even if every reading and the record is atomic.)

In C #, virtually nothing is guaranteed atomic. In short:

  • read 32 bit integer or float
  • reading link
  • write 32 bit integer or float
  • link record

guaranteed to be atomic (see specification for exact details.)

In particular, reading and writing a 64-bit integer or float is not guaranteed to be atomic. If you say:

 Cx = 0xDEADBEEF00000000; 

in one thread and

 Cx = 0x000000000BADF00D; 

in another thread, then this is possible in the third thread:

 Console.WriteLine(Cx); 

have written 0xDEADBEEF0BADF00D, although logically the variable never held this value. C # language reserves the right to make a record the long equivalent of writing two ints one by one, and in practice, some chips implement it this way. The stream switch after the first write may cause the reader to read something unexpected.

Long and short: do not share anything between two threads without blocking something. Castles are only slow when they are happy; if you have a performance problem due to competing castles, then fix any architectural flaw leading to competing castles. If locks are not approved and are still too slow, then you should consider moving to dangerous methods with a low lock level.

The general low-blocking technique to use here is, of course, calling Threading.Interlocked.Increment , which makes an integer increment a guaranteed atom. (Please note, however, that it still does not guarantee things like what happens if each of the two threads locks two different variables at different times and the other threads try to determine which increment happened "first ". C # does not guarantee that all contiguous sequences of events are scanned by all threads.)

+69
Jan 07 2018-11-17T00:
source share

No, it is not.

The analysis that you came up with is quite correct - the ++ (and -- ) operators are vulnerable to race conditions if they are not used with the corresponding locking semantics.

This is difficult to do correctly, but, fortunately, BCL has a ready-made solution for these specific cases:

You should use Interlocked.Increment if you want atomic increment operation. There is also Decrement and several other useful atomic operations defined on Interlocked .

Increases the given variable and saves the result as an atomic operation.

+28
Jan 07 '11 at 17:18
source share

No, i++ looks compact, but it’s really just a shorthand for i = i + 1 , and in this form it’s easier to see that it includes reading and writing β€œi”. Without blocking, it is simply unsafe.

2 other arguments:

  • `++ 'is not defined as thread safe
  • existence of Interlocked.Increment (ref int x)

Thread safety is rare and costly; it will be clearly advertised when available.

+7
Jan 07 2018-11-11T00:
source share



All Articles