Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is thread safe (C#) ? (Strings, arrays, ... ?)

I'm quite new to C# so please bear with me. I'm a bit confused with the thread safety. When is something thread safe and when something isn't?

Is reading (just reading from something that was initialized before) from a field always thread safe?

//EXAMPLE
RSACryptoServiceProvider rsa = new RSACrytoServiceProvider();
rsa.FromXmlString(xmlString);  
//Is this thread safe if xml String is predifined 
//and this code can be called from multiple threads?

Is accessing an object from an array or list always thread safe (in case you use a for loop for enumeration)?

//EXAMPLE (a is local to thread, array and list are global)
int a = 0;
for(int i=0; i<10; i++)
{
  a += array[i];
  a -= list.ElementAt(i);
}

Is enumeration always/ever thread safe?

//EXAMPLE
foreach(Object o in list)
{
   //do something with o
 }

Can writing and reading to a particular field ever result in a corrupted read (half of the field is changed and half is still unchanged) ?

Thank you for all your answers and time.

EDIT: I meant if all threads are only reading & using (not writing or changing) object. (except for the last question where it is obvious that I meant if threads both read and write). Because I do not know if plain access or enumeration is thread safe.

like image 882
Ben Avatar asked Apr 26 '11 17:04

Ben


People also ask

What is meant by thread-safe in C?

A threadsafe function protects shared resources from concurrent access by locks. Thread safety concerns only the implementation of a function and does not affect its external interface. In C language, local variables are dynamically allocated on the stack.

What is meant by thread-safe?

Thread safety is the avoidance of data races—situations in which data are set to either correct or incorrect values, depending upon the order in which multiple threads access and modify the data.

Is C write thread-safe?

write() is certainly thread-safe. The problem is that a partial write() could require multiple calls in order to completely write the data, and while that is "thread-safe" it could result in interleaved data.

Is open thread-safe C?

If you're running on a Unix-like OS, when open() is a direct system call, the answer is absolutely yes.


2 Answers

It's different for different cases, but in general, reading is safe if all threads are reading. If any are writing, neither reading or writing is safe unless it can be done atomically (inside a synchronized block or with an atomic type).

It isn't definite that reading is ok -- you never know what is happening under the hoods -- for example, a getter might need to initialize data on first usage (therefore writing to local fields).

For Strings, you are in luck -- they are immutable, so all you can do is read them. With other types, you will have to take precautions against them changing in other threads while you are reading them.

like image 194
Lou Franco Avatar answered Oct 13 '22 14:10

Lou Franco


Is reading (just reading from something that was initialized before) from a field always thread safe?

The C# language guarantees that reads and writes are consistently ordered when the reads and writes are on a single thread in section 3.10:


Data dependence is preserved within a thread of execution. That is, the value of each variable is computed as if all statements in the thread were executed in original program order. Initialization ordering rules are preserved.


Events in a multithreaded, multiprocessor system do not necessarily have a well-defined consistent ordering in time with respect to each other. The C# language does not guarantee there to be a consistent ordering. A sequence of writes observed by one thread may be observed to be in a completely different order when observed from another thread, so long as no critical execution point is involved.

The question is therefore unanswerable because it contains an undefined word. Can you give a precise definition of what "before" means to you with respect to events in a multithreaded, multiprocessor system?

The language guarantees that side effects are ordered only with respect to critical execution points, and even then, does not make any strong guarantees when exceptions are involved. Again, to quote from section 3.10:


Execution of a C# program proceeds such that the side effects of each executing thread are preserved at critical execution points. A side effect is defined as a read or write of a volatile field, a write to a non-volatile variable, a write to an external resource, and the throwing of an exception. The critical execution points at which the order of these side effects must be preserved are references to volatile fields, lock statements, and thread creation and termination. [...] The ordering of side effects is preserved with respect to volatile reads and writes.

Additionally, the execution environment need not evaluate part of an expression if it can deduce that that expression’s value is not used and that no needed side effects are produced (including any caused by calling a method or accessing a volatile field). When program execution is interrupted by an asynchronous event (such as an exception thrown by another thread), it is not guaranteed that the observable side effects are visible in the original program order.


Is accessing an object from an array or list always thread safe (in case you use a for loop for enumeration)?

By "thread safe" do you mean that two threads will always observe consistent results when reading from a list? As noted above, the C# language makes very limited guarantees about observation of results when reading from variables. Can you give a precise definition of what "thread safe" means to you with respect to non-volatile reading?

Is enumeration always/ever thread safe?

Even in single threaded scenarios it is illegal to modify a collection while enumerating it. It is certainly unsafe to do so in multithreaded scenarios.

Can writing and reading to a particular field ever result in a corrupted read (half of the field is changed and half is still unchanged) ?

Yes. I refer you to section 5.5, which states:


Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. In addition, reads and writes of enum types with an underlying type in the previous list are also atomic. Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic. Aside from the library functions designed for that purpose, there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.


like image 13
Eric Lippert Avatar answered Oct 13 '22 13:10

Eric Lippert