Does it mean that two threads can\'t change the underlying data simultaneously? Or does it mean that the given code segment will run with predictable results when multiple t
In essence, many things can go wrong in a multi threaded environment (instructions reordering, partially constructed objects, same variable having different values in different threads because of caching at the CPU level etc.).
I like the definition given by Java Concurrency in Practice:
A [portion of code] is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.
By correctly they mean that the program behaves in compliance with its specifications.
Contrived example
Imagine that you implement a counter. You could say that it behaves correctly if:
counter.next()
never returns a value that has already been returned before (we assume no overflow etc. for simplicity)A thread safe counter would behave according to those rules regardless of how many threads access it concurrently (which would typically not be the case of a naive implementation).
Note: cross-post on Programmers
A more informative question is what makes code not thread safe- and the answer is that there are four conditions that must be true... Imagine the following code (and it's machine language translation)
totalRequests = totalRequests + 1
MOV EAX, [totalRequests] // load memory for tot Requests into register
INC EAX // update register
MOV [totalRequests], EAX // store updated value back to memory
Yes and yes. It implies that data is not modified by more than one thread simultaneously. However, your program might work as expected, and appear thread-safe, even if it is fundamentally not.
Note that the unpredictablility of results is a consequence of 'race-conditions' that probably result in data being modified in an order other than the expected one.
Instead of thinking of code or classes as thread safe or not, I think it is more helpful to think of actions as being thread-safe. Two actions are thread safe if they will be behave as specified when run from arbitrary threading contexts. In many cases, classes will support some combinations of actions in thread-safe fashion and others not.
For example, many collections like array-lists and hash sets will guarantee that if they are initially accessed exclusively with one thread, and they are never modified after a reference becomes visible to any other threads, they may be read in arbitrary fashion by any combination of threads without interference.
More interestingly, some hash-set collections such as the original non-generic one in .NET, may offer a guarantee that as long as no item is ever removed, and provided that only one thread ever writes to them, any thread that tries to read the collection will behave as though accessing a collection where updates might be delayed and occur in arbitrary order, but which will otherwise behave normally. If thread #1 adds X and then Y, and thread #2 looks for and sees Y and then X, it would be possible for thread #2 to see that Y exists but X doesn't; whether or not such behavior is "thread-safe" would depend upon whether thread #2 is prepared to deal with that possibility.
As a final note, some classes--especially blocking communications libraries--may have a "close" or "Dispose" method which is thread-safe with respect to all other methods, but no other methods that are thread-safe with respect to each other. If a thread performs a blocking read request and a user of the program clicks "cancel", there would be no way for a close request to be issued by the thread that's attempting to perform the read. The close/dispose request, however, may asynchronously set a flag which will cause the read request to be canceled as soon as possible. Once close is performed on any thread, the object would become useless, and all attempts at future actions would fail immediately, but being able to asynchronously terminate any attempted I/O operations is better than require that the close request be synchronized with the read (since if the read blocks forever, the synchronization request would be likewise blocked).
I like the definition from Brian Goetz's Java Concurrency in Practice for its comprehensiveness
"A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code."
An easier way to understand it, is what make code not thread-safe. There's two main issue that will make a threaded application to have unwanted behavior.
Accessing shared variable without locking
This variable could be modified by another thread while executing the function. You want to prevent it with a locking mechanism to be sure of the behavior of your function. General rule of thumb is to keep the lock for the shortest time possible.
Deadlock caused by mutual dependency on shared variable
If you have two shared variable A and B. In one function, you lock A first then later you lock B. In another function, you start locking B and after a while, you lock A. This is a potential deadlock where first function will wait for B to be unlocked when second function will wait for A to be unlocked. This issue will probably not occur in your development environment and only from time to time. To avoid it, all locks must always be in the same order.