Why does this Java program terminate despite appearing that it shouldn't?
stackoverflow.com
stackoverflow.com
I remember grepping the source for pthread_mutex or pthread_cond and slowly realizing that whoever wrote the code didn't even see the need for locks. To be fair, I later heard it was some poor hardware guy who knew some C who got roped into writing the software as an afterthought to show off the awesome hardware, a common problem with hardware companies.
"Oh, you wrote a quick demo for the sales people? Well, now it's a product sold for some ten thousand!"
That is often why soldiers on the ground end up with overpriced yet crappy tools and weapons.
The good news is that if Skynet ever happens, it will probably crash before it can take over the world.
A lot of things are possible but they are not happening the incentives are just not there.
currentPos = new Point(currentPos.x+1, currentPos.y+1); does a few things, including writing default values to x and y (0) and then writing their initial values in the constructor. Since your object is not safely published those 4 write operations can be freely reordered by the compiler / JVM.
So from the perspective of the reading thread, it is a legal execution to read x with its new value but y with its default value of 0 for example. By the time you reach the println statement (which by the way is synchronized and therefore does influence the read operations), the variables have their initial values and the program prints the expected values.
I'm not anywhere near smart or careful enough for that... I think I'll stick with Haskell.
1. Thou Shalt Not touch shared data without synchronization.
You must know what data is shared, and you must synchronize all access to shared data (with one exception, when all access is read-only).
People try to find exceptions to this One Commandment. They think, I'm only writing one value, so what's the harm? Well, this is the harm. Follow the One Commandment and you'll be safe(r).
Classes should be immutable unless there's a very good reason to make them mutable
Immutability makes life a LOT easier. A great example is the well designed joda-time vs the disaster that is the the mutable Date and Calendar core language classes.
Referring partly to your parent comment... it's instructive to look at the String implementation.
It's immutable, but they have to jump through a few hoops to do it properly... internally, a String has a private char array. An array is not immutable, so the code has to be very careful to never expose that char array externally.
Because of that, calling toCharArray() will copy the internal array and return the copy -- that one's fairly obvious. But less obviously, a String constructed with a char array must also make a copy... otherwise the calling code might then modify the array after creating the String with it.
So sure, immutable objects are possible, and widely encouraged in Java, but they're easy to do wrongly/incompletely.
Synchronization is like commas in English. People don't really know the rules, and there is danger in putting in too many as well as too few. You should never put in a lock without understanding the mechanics of the datum you're touching. Some times you won't need synchronization at all.
// Thread 1
atomic_inc(&x);
atomic_inc(&y);
// Thread 2
local_y = atomic_read(&y);
local_x = atomic_read(&x);
If you go through it logically, it's always in a valid state, right?No. You need explicit synchronization. If we start at x=1, y=1, then thread 2 can see x=1, y=2, which seems impossible!
Or in short, your exception sucks. (By "sucks" I mean it is not sufficiently detailed enough to prevent errors.)
For example, suppose we have:
A = 0
B = 0
Producer:
while true:
AtomicIncrement A
AtomicIncrement B
Consumer:
while true:
postA = AtomicDecrement A
postB = AtomicDecrement B
assert postA == postB // wrong
The assertion is wrong, when you're dealing with relaxed atomics. For example, the producer can be optimized into this either by the compiler or by caching layers: int savedUpA = 0
while true:
savedUpA++
if (savedUpA == 100)
AtomicAdd A, 100
AtomicIncrement B
In which case the consumer will often see that postA != postB.Thankfully, languages are apparently converging on "every atomic write is a release barrier" and "every atomic read is an acquire barrier", which makes these sorts of optimizations illegal (releasing B's new value requires releasing A's new value).
Sometimes just making new copy and passing that around might not cause that much of a performance penalty vs the time spent debugging synchronization problems.
That code is terrible from a thread safety perspective. If the author didn't read up on how to write good thread-safe code, it's unlikely he'd read up on Haskell, so he'd probably write bad code there, too.
The notion that currentPos could be set to the new Point before the Point(int x, int y) constructor completed was completely surprising to me.
Is that something that was obvious to you, or do you have other reasons to dislike it?
It's a pretty straightforward recipe for disaster.
I would have thought that the order of operations would be:
1) Read value from currentPos.x and add 1. Do same for y.
2) Pass values to constructor
3) Construct the new object
3a) init values with 0
3b) assign new values to x and y
4) Assign the newly constructed object's pointer to currentPos.I thought that the problem lay in 4 where you might read a partial update of the pointer, possibly giving weird results. Is he saying that it might get assigned first and then constructed afterwards?
Yes. In some versions of java the code: x = new X() results in assigning to x a reference to a new uninitialized object X and then a call to the constructor.
Reference assignment in java is always atomic, it is guaranteed by the memory model.
The issue here is the lack of a write barrier at the point of publishing the reference to the newly constructed object, and the lack of a read barrier at the point of reading the reference to the newly constructed object. You want to stop both writes moving forward in time (the writes in the constructor happening after the write that publishes the object) and reads moving backwards in time (the reads on the other thread reading the old values of the constructed object, rather than the initialized values - may be caused by e.g. satisfying the read from per-CPU cache).
Java's volatile acts both ways; writes are write barriers and reads are read barriers.
Also, "reading of the data is not atomic" - you can switch threads in the middle of reading the data.
In order to program THREADED CODE sanely with that in mind, you need to minimize the amount of shared data, and be sure to lock / synchronize around the writing AND READING of any shared data.
If you're not writing threaded code then there is no shared data, and you don't care about these rules. Writing threaded code isn't like dusting crops, but it's not impossible.
EDIT: you also said "the println statement [...] is synchronized" but it doesn't look like that's true - there's nothing in the synchronized(this) {} block, and even if there was, all it would do is keep "this" from entering that block twice; it has no effect on other threads in this code.
Seems to me, either there's something synchronized in Integer.toString (which seems undesirable and therefore unlikely) or, statistically, in the rare cases that the writes don't take effect in time for the 'if' predicate, they do take effect a few nanoseconds later, in time for the conversions involved in the string construction. (Actually p.x is the only one at risk here, statistically speaking; the conversion of its value to a string will take plenty long enough for the write of p.y to take effect. Combine that with the fact that the write of p.x probably still precedes that of p.y, so that the one that's wrong in the 'if' statement is probably p.y, and you see that the odds of the wrong values being printed are vanishingly small.)
The exception is if you have tight control over your environment, have tests in place to verify that environment upgrades do not break your assumptions, and you desperately need to bend the rules, but even then, you should look really hard for better alternatives.
So "println() uses synchronized internally" means two println statements will never overlap each other, but still says nothing about their interaction with other objects, right? Does nothing to prevent switching threads in the middle of the println and getting two different values?
The bottom line is that the Point object should have been immutable, which would have made it safe for publication. That requires its fields to be final (among other things), which was not the case.
These are tricks the compiler/VM can use, because (unless you say otherwise in code) it's assumed that there's no sharing data between threads.
Most programmers (regardless of the language) just learn the rules about programming with threads -- they don't care why exactly following the rules is important.
I agree with you, one must know why rules are important.. but in large systems, it's better if the system/language enforces this separation of data (praise Erlang).
The best answers would ideally answer the question as asked (or explain why it can't be done) and also show a still more excellent way.
[1]: http://weblogs.asp.net/alex_papadimoulis/archive/2005/05/25/...
[2]: http://meta.stackoverflow.com/questions/66377/what-is-the-xy...
There are times I've asked how to do X, and for various reasons X is really, no kidding, exactly what wanted to do. Still, numerous people would question my desire to do X, turning the discussion into an inquisition on motives or skill comprehension.
I'm sure in some odd way they all meant well, but they were spending a lot of cycles not actually answering the question.
In those cases the better strategy is to, under some crafty pretext, bluntly assert that X cannot be done.
This will evoke numerous rebuttals with full details on just how incredibly wrong and foolish that claim is.
Both cases play to a trait all too common to many people on discussion boards: replying to questions with the primary goal of showing that you are, in fact, smarter than everyone else.
Only, more often than not, people think they always know better and everyone asking a question must either not know the proper way of doing things, and why in the world are they trying to do <question_asked> ? This then leads to a debate about me trying to solve problem X which requires me to solve Y which requires me to do Z, which led me to ask the question. At the end, I get the exact answer I was looking for, but that took longer than necessary because other were looking at it the same way you described, that it's the XY problem. I can't help but feel that it mostly just wasted my time a lot.
You don't always have to know the entire story behind the code to give straight answers, is all I'm saying. :)
One thing I've found is that, beyond a pretty low floor, more details often means less answers. If you, forex, post your C code and ask why it doesn't work on IRIX, people will say "it must be something weird about IRIX, I don't care about that" and ignore you. If you post it without mentioning the OS, you can get some good answers.
Based on study and years of experience I conclude that the ONLY way to build such as system is to use a time-triggered approach as opposed to event-triggered. No threads. Only one interrupt --the timer-- in the entire system if at all possible.
This is where I fall back to the raw simplicity of C. You really have to work hard to do stupid shit like threads in C. By that I mean that you have to go out of your way to bring in the code and a framework that might allow you to do that. I've successfully written and applied at least a couple of RTOS's for use in mission critical applications (definition: you fuck up and someone gets hurt or dies). Again, only one interrupt. No threads. Carefully --and I do mean very carefully-- shared data between tasks only if absolutely necessary.
A corollary to this is that I could not fathom programming an electron microscope (the subject of the SO question) or anything that might lead to millions of dollars in losses with Java. Couldn't pay me enough.
Anyone interested in working with hard real-time embedded systems would be wise to study the following well-known books:
- Patterns for Time-Triggered Embedded Systems, Michael J. Pont
- Embedded Systems Building Blocks, Jean J. Labrosse
- uC/OS-III, Jean J. Labrosse (uC/OS-II by the same author includes
the source to the prior version of the OS)
- Doing Hard Time, Grady Booch
- Operating System Concepts, Silbershatz, Galvin, Gagne
There are other good books on the subject. The above should provide a very solid foundation.Don't just hack away without the necessary background. The consequences of making mistakes out of sheer ignorance could be dire.
Honestly, I got some mild goose-bumps after realizing the number of Zeroes that 12 million had.
Anyway, you could do it in Go like this: http://play.golang.org/p/3Wy_S42jVj
basically what you do is you create a goroutine that reads a pointer to the Point value, checks it, and if it's bad, exits. In your main loop, send a * Point down the channel. That basically means: I made this thing. It's yours now. Do what you want with it. Then in the reporting channel, the value is read and checked. The same pointer is sent back in a reply, meaning "I'm done with this, you can have it back now". You almost certainly shouldn't be doing this; I'm just doing this to emulate the fact that the original example is using the same reference from both threads. Yes, this is very, very weird and no, you should not do this in your own programs. Anyway, we take that pointer back, dereference it, and assign it to a new Point value, which is completely weird and I still don't understand. (presumably the original author mistakenly thought this was an atomic way to set both fields on the Point.) In this way, the two goroutines (the main and reporting goroutine) are able to use channels to synchronize access to some shared memory.
This is a pretty silly use of concurrency, though, because in this case, it's probably more clear to just use a mutex to lock and unlock your Point. Again, yes, this is sloppy and weird, but it represents the same behavior as the original program, but properly synchronized.
You assuming a "real" producer-consumer relationship. But the posted code seems to imply a sort of "supervisor-worker" relationship.
The "supervisor" "snoops" on the worker's state and raises an alarm if the worker is doing something weird.
As you stated at the end, synchronizing around currentPos seems to be most reasonable solution (assuming that's possible). That guarantees that no Point method is running while currentPos's state is being examined.
Anyway, what you're describing is pretty easy too. Basically all you do is make a channel of Point, and have the supervisor read on that. The worker just does some work, and tries to send his value down the channel. If someone's listening, send the value. This is pretty straightforward, but probably not safe in the real world, because the worker just keeps on working; it doesn't wait for a confirmation that its work is ok. http://play.golang.org/p/J8Xgh8S18b
If you want to structure it such that the supervisor can stop the worker, ask the worker what it's doing, look at the data, and then reply with "ok, you can continue now", there's a handful of ways to do it. Now we're getting pretty real-world, and things get a little bit more intricate, but you can do it like this: http://play.golang.org/p/hXYNmCm8lg
the trick being that you send a channel over another channel. There's a handful of ways you could structure this; there may be a cleaner way.
I think the chief problem is that the developer hadn't learned the basics of multithreaded programming yet, and didn't realize s/he needed to know them.
That's an extremely harsh way to learn a little lesson, regardless.
IMO raw threads are too dangerous to use as anything other than a primitive to implement higher-level concurrency on.
If the hardware can be destructive under the control of software then you must have hardware interlocks, not just software safety features.
Also on that list (from memory).
* AT&T's switch cascade failure * Mars Climate Orbiter * Ariane 5
He also took us through some bugs in code he'd written when he was doing massive telecomm's systems.
I came away with a few lessons.
* If it can't fail, test it twice. * If it's designed so it can't possibly fail, test it three times. * All code is buggy.
When faced with this kind of requirements, I always lift my eyes right above my screen, where it is written:
> The major difference between a thing that might go wrong and a thing that cannot possibly go wrong is that when a thing that cannot possibly go wrong goes wrong it usually turns out to be impossible to get at or repair.
And for emphasis, next to it is a poster of a nuclear island cut-out.
Sure enough, we once had a motor controller break where the problem was interconnecting wiring...
For those who haven't read it, http://sunnyday.mit.edu/papers/therac.pdf
1. Those who read about Therac-25 and decide never to work on any systems where bugs could threaten lives (your chosen course, and mine).
2. Those who read about Therac-25, get frightened, and work very carefully on such systems.
3. Those who read about Therac-25 and think, "Those idiots! Good thing I'd never make a mistake like that."
The prevalence of (3) in all professions and walks of life is kind of frightening.
If you dig into the details of why its programmers and their managers killed people, it's very easy to say "I'd never be that irresponsible", but still screw up with much more subtle bugs.
:)
But it can be stressful to write software that has a very direct impact on peoples lifes. While I was rolling out an updated version of an inhouse application a serious bug was discovered. The application was used as part of chemotherapy follow-up/planning and on some occasions it gave the wrong answer for a test. I discovered that the bug was old and that wrong answers had been given for a long period. Personally I was relieved that I had not caused the bug, but from a medical perspective it would have been better if the bug was new and had only affected very few patients.
My takeaway from that experience is that care should be taken when writing critical software, but also that we will make mistakes and it is very important to always focus on how we can make fewer mistakes instead of pointing fingers.
Even if obligation to publish source code were to harm companies (which might even not be the case) the benefit it would bring to the consumers and whole ecosystem is more important.
Companies don't need special protection. The most important advantage of a company is that it can die without killing all people who work there and destroying all its assets. This allows companies to take risks no sane person would take if he were to be responsible with all his money (both savings and potential debt).
He's no doubt learned some important lessons, but I can't find destroying $12 million in equipment in any way funny. [c0deporn has updated his original to the more accurate and appropriate "interesting".]
If someone broke a $12m machine, surely their career would be over.
Who would you rather have working on your $12m machine, someone with no real experience with that sort of hardware or someone with plenty of experience and some painfully learned lessons about exactly how careful you have to be when working with brittle $12m machines.
There are two philosophies of justice: retributive and utilitarian. Retributive justice is about punishing the guilty. If you destroy a $12 million machine, you deserve to have $12 million taken away from you. Most people don't have $12 million, so the retributive boss will take away as much as he can: fire you and file suit if he can and badmouth you to other companies so you never work again.
Utilitarian justice is about preventing future harm. It's not about punishing the guy who pushed the button on destroying $12 million of hardware, it's about preventing future hardware losses. You fire the guy if you think he's likely to destroy more hardware in the future, because maybe he was negligent and careless or even malicious. You keep the guy if he was just in the wrong place at the wrong time, and any other competent employee would have made the same call and inflicted the same loss.
So while the "$12 million in training" line is a great ice-breaker for making the poor guy feel better, if someone broke a $1 million machine, then a $2 million machine (after all, he has $1 million of training now), then a $3 million machine, then a $6 million machine, would you say, "Great, he's got $12 million of training! Let's put him in charge of our $12 million machine!"?
Another Lockheed test pilot wrecked a F-16E at an airshow practice and ejected with injuries now flies F-35s.
The only possible explanation is that the JIT decided to reorder the execution so the variable was set to memory allocated for the object, and then ran the objects constructor.
It's all very surprising behavior.
That's not to say another concurrent access can't sneak in between the block and the next statement, of course, but it does change the behaviour somewhat. But I can't really think of a use case.
As a side effect, it may also act as a memory barrier.
for all actors actor.tick(timeDelta);
1) Include software controls to limit motor position 2) Include hardware kill switch to prevent collisions. 3) Drive unit to the outermost SAFE motor position. 4) Motor limit drops into worm gear 5) Send unit back to original position. 6) Unit doesn't move as worm gear eats limit cable. 7) Since the unit didn't actually move, the software limits are now compared with faulty data. 8) Send the unit out to the far edge again 9) Since the software positions are incorrect, the software limits won't help. 10) Since the limit cable was eaten by the gear, the contact switch won't help. 11) Hear super-mirror array drive into concrete wall.
Of course, having a hardware limit switch the trigger on an open circuit would have fixed that problem. Until the time that a faulty solder joint shorts the switch and the mirror drives into the wall.
So you can add in a hardware encoder to check the physical position. Which saves you until the unit is manually moved next to the wall between runs without updating the position in software. Since the encoder only gives relative position, the software limits, encoder, and shorted limit switch still gleefully watch as you again drive the super-mirror into a wall.
Unfortunately non-software guys often have a lack of appreciation for how subtle some software bugs can be. Re. the mentioned Therac-25 incident in this thread.
YES, I have written tests in multi-threaded situations before. Your aversion to trying it doesn't make my statement wrong.