Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
282 views
in Technique[技术] by (71.8m points)

c# - Is the ++ operator thread safe?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As other answers have pointed out, no, ++ is not "threadsafe".

Something that I think will help as you learn about multithreading and its hazards is to start being very precise about what you mean by "threadsafe", because different people mean different things by it. Essentially the aspect of thread safety you are concerned about here is whether the operation is atomic or not. An "atomic" operation is one which is guaranteed to not be halfway complete when it is interrupted by another thread.

(There are plenty of other threading problems that have nothing to do with atomicity but which may still fall under some people's definitions of thread safety. For example, given two threads each mutating a variable, and two threads each reading the variable, are the two readers guaranteed to agree on the order in which the other two threads made mutations? If your logic depends on that, then you have a very difficult thread safety problem to deal with even if every read and write is atomic.)

In C#, practically nothing is guaranteed to be atomic. Briefly:

  • reading a 32 bit integer or float
  • reading a reference
  • writing a 32 bit integer or float
  • writing a reference

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

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

C.x = 0xDEADBEEF00000000;

on one thread, and

C.x = 0x000000000BADF00D;

on another thread, then it is possible to on a third thread:

Console.WriteLine(C.x);

have that write out 0xDEADBEEF0BADF00D, even though logically the variable never held that value. The C# language reserves the right to make writing to a long equivalent to writing to two ints, one after the other, and in practice some chips do implement it that way. A thread switch after the first of the writes can cause a reader to read something unexpected.

The long and short of it is: do not share anything between two threads without locking something. Locks are only slow when they are contented; if you have a performance problem because of contended locks then fix whatever architectural flaw is leading to contended locks. If the locks are not contended and are still too slow, only then should you consider going to dangerous low-lock techniques.

The common low-lock technique to use here is of course to call Threading.Interlocked.Increment, which does an increment of an integer in a manner guaranteed to be atomic. (Note however that it still does not make guarantees about things like what happens if two threads are each doing interlocked increments of two different variables at different times, and other threads are trying to determine which increment happened "first". C# does not guarantee that a single consistent ordering of events is seen by all threads.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...