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

前端 未结 18 1764
孤独总比滥情好
孤独总比滥情好 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 13:59

    At least in C++, I think of thread-safe as a bit of a misnomer in that it leaves a lot out of the name. To be thread-safe, code typically has to be proactive about it. It's not generally a passive quality.

    For a class to be tread-safe, it has to have "extra" features that add overhead. These features are part of the implementation of the class and generally speaking, hidden from the interface. That is, different threads can access any of the class' members without ever having to worry about conflicting with a concurrent access by a different thread AND can do so in a very lazy manner, using plain old regular human coding style, without having to do all that crazy synchronization stuff that is already rolled into the guts of the code being called.

    And this is why some people prefer to use the term internally synchronized.

    Terminology Sets

    There are three main sets of terminology for these ideas I have encountered. The first and historically more popular (but worse) is:

    1. thread safe
    2. not thread safe

    The second (and better) is:

    1. thread proof
    2. thread compatible
    3. thread hostile

    A third is:

    1. internally synchronized
    2. externally synchronized
    3. unsynchronizeable

    Analogies

    thread safe ~ thread proof ~ internally synchronized

    An example of an internally synchronized (aka. thread-safe or thread proof) system is a restaurant where a host greets you at the door, and disallows you from queueing yourself. The host is part of the mechanism of the restaurant for dealing with multiple customers, and can use some rather tricky tricks for optimizing the seating of waiting customers, like taking the size of their party into account, or how much time they look like they have, or even taking reservations over the phone. The restaurant is internally synchronized because all of this is included "behind the scenes" when you interact with it. You, the customer, don't do any of it. The host does all of it for you.

    not thread-safe (but nice) ~ thread compatible ~ externally synchronized ~ free-threaded

    Suppose that you go to the bank. There is a line, i.e. contention for the bank tellers. Because you're not a savage, you recognize that the best thing to do in the midst of contention for a resource is to queue like a civilized being. No one technically makes you do this. We hope you have the necessary social programming to do it on your own. In this sense, the bank lobby is externally synchronized. Should we say that it's thread-unsafe? that's what the implication is if you go with the thread-safe, thread-unsafe bipolar terminology set. It's not a very good set of terms. The better terminology is externally synchronized, The bank lobby is not hostile to being accessed by multiple customers, but it doesn't do the work of synchronizing them either. The customers do that themselves.

    This is also called "free threaded," where "free" is as in "free from lice"--or in this case, locks. Well, more accurately, synchronization primitives. That doesn't mean the code can run on multiple threads without those primitives. It just means it doesn't come with them already installed and it's up to you, the user of the code, to install them yourself however you see fit. Installing your own synchronization primitives can be difficult and requires thinking hard about the code, but also can lead to the fastest possible program by allowing you to customize how the program executes on today's hyperthreaded CPUs.

    not thread safe (and bad) ~ thread hostile ~ unsynchronizeable

    An example everyday analogy of a thread-hostile system is some jerk with a sports car refusing to use their blinkers and changing lanes willy-nilly. Their driving style is thread hostile or unsychronizable because you have no way to coordinate with them, and this can lead to contention for the same lane, without resolution, and thus an accident as two cars attempt to occupy the same space, without any protocol to prevent this. This pattern can also be thought of more broadly as anti-social, which I prefer because it's less specific to threads and so more generally applicable to many areas of programming.

    Why thread safe et al. are a bad terminology set

    The first and oldest terminology set fails to make the finer distinction between thread hostility and thread compatibility. Thread compatibility is more passive than so-called thread safety, but that doesn't mean the called code is unsafe for concurrent thread use. It just means it's passive about the synchronization that would allow this, putting it off to the calling code, instead of providing it as part of its internal implementation. Thread compatible is how code should probably be written by default in most cases but this is also sadly often erroneously thought of as thread unsafe, as if it's inherently anti safety, which is a major point of confusion for programmers.

    NOTE: Many software manuals actually use the term "thread-safe" to refer to "thread-compatible," adding even more confusion to what was already a mess! I avoid the term "thread-safe" and "thread-unsafe" at all costs for this very reason, as some sources will call something "thread-safe" while others will call it "thread-unsafe" because they can't agree on whether you have to meet some extra standards for safety (synchronization primitives), or just NOT be hostile to be considered "safe". So avoid those terms and use the smarter terms instead, to avoid dangerous miscommunications with other engineers.

    Reminder of our goals

    Essentially, our goal is to subvert chaos.

    We do that by creating deterministic systems we can rely on. Determinism is expensive, mostly due to the opportunity costs of losing parallelism, pipelining, and reordering. We try to minimize the amount of determinism we need to keep our costs low, while also avoiding making decisions that will further erode what little determinism we can afford.

    Synchronization of threads is about increasing the order and decreasing the chaos. The levels at which you do this correspond to the terms mentioned above. The highest level means that a system behaves in an entirely predictable manner every time. The second level means that the system behaves well enough that calling code can reliably detect unpredictability. For example, a spurious wakeup in a condition variable or a failure to lock a mutex because it's not ready. The third level means that the system doesn't behave well enough to play with anyone else and can only EVER be run single-threaded without incurring chaos.

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

    Thread-safe code is code that will work even if many Threads are executing it simultaneously.

    http://mindprod.com/jgloss/threadsafe.html

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

    Let's answer this by example:

    class NonThreadSafe {
    
        private int counter = 0;
    
        public boolean countTo10() {
            count = count + 1;
            return (count == 10);
        }
    

    The countTo10 method adds one to the counter and then returns true if the count has reached 10. It should only return true once.

    This will work as long as only one thread is running the code. If two threads run the code at the same time various problems can occur.

    For example, if count starts as 9, one thread could add 1 to count (making 10) but then a second thread could enter the method and add 1 again (making 11) before the first thread has a chance to execute the comparison with 10. Then both threads do the comparison and find that count is 11 and neither returns true.

    So this code is not thread safe.

    In essence, all multi-threading problems are caused by some variation of this kind of problem.

    The solution is to ensure that the addition and the comparison cannot be separated (for example by surrounding the two statements by some kind of synchronization code) or by devising a solution that does not require two operations. Such code would be thread-safe.

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

    Yes and no.

    Thread safety is a little bit more than just making sure your shared data is accessed by only one thread at a time. You have to ensure sequential access to shared data, while at the same time avoiding race conditions, deadlocks, livelocks, and resource starvation.

    Unpredictable results when multiple threads are running is not a required condition of thread-safe code, but it is often a by-product. For example, you could have a producer-consumer scheme set up with a shared queue, one producer thread, and few consumer threads, and the data flow might be perfectly predictable. If you start to introduce more consumers you'll see more random looking results.

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

    Simply - code will run fine if many threads are executing this code at the same time.

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

    To complete other answers:

    Synchronization is only a worry when the code in your method does one of two things:

    1. works with some outside resource that isn't thread safe.
    2. Reads or changes a persistent object or class field

    This means that variables defined WITHIN your method are always threadsafe. Every call to a method has its own version of these variables. If the method is called by another thread, or by the same thread, or even if the method calls itself (recursion), the values of these variables are not shared.

    Thread scheduling is not guaranteed to be round-robin. A task may totally hog the CPU at the expense of threads of the same priority. You can use Thread.yield() to have a conscience. You can use (in java) Thread.setPriority(Thread.NORM_PRIORITY-1) to lower a thread's priority

    Plus beware of:

    • the large runtime cost (already mentionned by others) on applications that iterate over these "thread-safe" structures.
    • Thread.sleep(5000) is supposed to sleep for 5 seconds. However, if somebody changes the system time, you may sleep for a very long time or no time at all. The OS records the wake up time in absolute form, not relative.
    0 讨论(0)
提交回复
热议问题