What is the meaning of the term “thread-safe”?

前端 未结 18 1766
孤独总比滥情好
孤独总比滥情好 2020-11-22 13:51

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

相关标签:
18条回答
  • 2020-11-22 14:18

    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)
    • all values from 0 to the current value have been returned at some stage (no value is skipped)

    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

    0 讨论(0)
  • 2020-11-22 14:19

    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
    
    1. The first condition is that there are memory locations that are accessible from more than one thread. Typically, these locations are global/static variables or are heap memory reachable from global/static variables. Each thread gets it's own stack frame for function/method scoped local variables, so these local function/method variables, otoh, (which are on the stack) are accessible only from the one thread that owns that stack.
    2. The second condition is that there is a property (often called an invariant), which is associated with these shared memory locations, that must be true, or valid, for the program to function correctly. In the above example, the property is that “totalRequests must accurately represent the total number of times any thread has executed any part of the increment statement”. Typically, this invariant property needs to hold true (in this case, totalRequests must hold an accurate count) before an update occurs for the update to be correct.
    3. The third condition is that the invariant property does NOT hold during some part of the actual update. (It is transiently invalid or false during some portion of the processing). In this particular case, from the time totalRequests is fetched until the time the updated value is stored, totalRequests does not satisfy the invariant.
    4. The fourth and final condition that must occur for a race to happen (and for the code to therefore NOT be "thread-safe") is that another thread must be able to access the shared memory while the invariant is broken, thereby causing inconsistent or incorrect behavior.
    0 讨论(0)
  • 2020-11-22 14:21

    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.

    0 讨论(0)
  • 2020-11-22 14:23

    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).

    0 讨论(0)
  • 2020-11-22 14:24

    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."

    0 讨论(0)
  • 2020-11-22 14:24

    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.

    0 讨论(0)
提交回复
热议问题