Out of Thin Air Safety

前端 未结 2 1316
夕颜
夕颜 2021-01-15 05:27

Java Concurrency in Practice explains this concept:

When a thread reads a variable without synchronization, it may see a stale value, but at least i

相关标签:
2条回答
  • 2021-01-15 05:52

    "Out-of-thin-air safety" is indeed a much weaker guarantee than e.g. "sequential consistency", but in some sense one might call it "strong." Namely, if your system provides OOTA-safety, you can reason about your programs much better than if your system didn't provide it. If you're using a system that doesn't provide OOTA-safety, you're basically screwed.

    Hans Boehm and Brian Demsky recently wrote a paper on the topic titled "Outlawing ghosts: avoiding out-of-thin-air results" (PDF available on ACM.org). They give some really good examples of how a non-OOTA-safe system might work, and what kinds of bugs might crop up in such a system.

    The basic idea is that some systems are allowed to do speculative execution, including speculative stores to memory (cache) which can later be undone if the system's speculation turns out to be incorrect. This works great in single-threaded systems, but in multi-threaded systems it is possible for two threads' speculations to feed on each other, creating a "runaway rumor mill": Processor A believes that x=42 because Processor B speculatively stored 42 there, but Processor B only stored x=42 because Processor A told it that y=17... but Processor A was merely speculating based on the assumption that x=42!

    void rivera() {                 void lemon() {
        if (x == 42) {                  if (y == 17) {
            y = 17;                         x = 42;
        }                               }
    }                               }
    

    A "non-OOTA-safe" system might rewrite these methods to look like (in pseudo-Python-Javascript syntax, sorry)

    void rivera() {
        assert(y not in cache);  // for the sake of argument
        cache.y = 17;  // for the sake of speed, speculatively report that y=17
        if (x not in cache) {
            cache.x = x;  // meanwhile, slowly fetch the real value of x
        }
        if (cache.x != 42) {
            delete cache.y;  // discard the earlier, speculative write
        }
        // and then later write cache.y back into the y in main memory
    }
    

    You can see how it would be a huge problem if lemon() trusted rivera()'s speculative report that cache.y = 17 and vice versa. We could end up, after both methods have completed, with the situation that x=42 and y=17 even when neither of them started out that way!

    I know people usually rely on time-travel paradox metaphors to describe how the values 42 and 17 end up in main memory "out of thin air", but I think the cable-news metaphor is more accurate. ;)

    0 讨论(0)
  • 2021-01-15 06:04

    Is this type of safety weak since it may include a stale value?

    Yes. The quote from "Java Concurrency in Practice" is trying to point out that your number may be 0 or 42 depending on the race conditions inherent with accessing unsynchronized fields but it won't be (let's say) 1 -- the value will not come "out-of-thin-air". It may be stale and, with objects and possibly even long 64-bit values depending on your hardware architecture, may also be partially updated, but it won't have some random value.

    In your example the number was initialized to 0 and then set by the main thread to be 42 so that is the possible values for number within ReaderThread.

    Edit:

    As Voo and yshavit point out, the JLS section 17.7 specifically mentions that there are architectures that implement 64-bit operations as 2 separate 32-bit operation that can be interrupted. This means that a thread might see only half of another threads' update to a field. Although not "out of thin air", the resulting value would seem to be one that was not set by any thread because of bitwise number representations.

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