The Tell-Tale Compiler
When I taught courses that included modules about achieving parallel correctness, I always recommended that analysis tools should only evaluate unoptimized code. Since you aren't looking for execution speed, yet, in your development, the code can run slower than desired during analysis. The tools I've had the chance to use could better point out source code lines correctly within unoptimized code and unanticipated problems from optimized code modifications were removed from consideration. My parting advice to students about tuning for correctness was: "If your code has errors when running with optimizations but doesn't exhibit those problems after compiling without optimizations, the source of the problem is more likely the compiler (and its optimizations) than something wrong in your code."
More Insights
White Papers
- A How-To Guide on Using Cloud Services for Security-Rich Data Backup
- How to test and launch a world-class application
Reports
- Best Practices: Using Apple's Global Proxy to Boost Mobile Security
- InformationWeek 2013 IT Spending Priorities Survey
Webcasts
- The Untapped Potential of Mobile Apps for Commercial Customers
- Secure Cloud: Taking Advantage of the Intelligent WAN
I want to show one more example of how a compiler can lead to a problem for the unwary programmer. I got this example from Herb Sutter and I thought it was very subtle and clever, so I wanted to share it with you. (Any errors in the explanation or description below are my fault.) Consider the following switch statement on the shared integer x.
if (x > 0 && x < 4) {
switch (x) {
case 1: . . .; break;
case 2: . . .; break;
case 3: . . .; break;
}
. . .
}
The conditional expression guarantees that the switch will only be executed if the value of x is one of three values: 1, 2, or 3. The compiler is free to optimize the switch into a jump table indexed by the value in x. If, after thread T5 has executed the conditional test and will next enter the "then" block, another thread, T8, updates the value of x to, say, 10, what code does the switch execute? T5 will jump to the code whose address is held in the tenth element of a three-element table. I'm tempted to make reference to the phrase "taking a long walk off a short pier," but I will refrain (even though I guess I just did).
I hope that someone programming a threaded application would not put such a faux pas into their code. An easy solution to the above is to do a protected read of x just before the conditional test and store the results into a temporary local variable. The local variable would be used in the conditional expression and as the selector value in the switch statement. The compiler can implement the jump table and there will be no out of bounds access to the table if the value of x is changed by another thread.
Unfortunately, applications aren't written by a single programmer too often these days. If the programmer of the switch code is unaware that the value of x can be altered by an external thread, the proper protection against the data race won't be implemented. Even if a solo programmer is parallelizing a serial code, she could overlook the interaction of the data race on the switch or even assume that the conditional expression will be able to guard against errant behavior.
One other related potential cause of erroneous execution is out-of-order execution at the instruction level, but I've run out of space.
To summarize from this and my previous post, let me strongly recommend that all possible data races within your code be protected in one fashion or other. Even if you feel that you've buried the race under conditional tests or proof of the data race being benign, the programming language, the compiler, or the hardware may cause application failures. These can be like a loud and steady drum beat that drives you to your wits' end and has you tearing up your code like a man possessed. Well, maybe that's a bit overly dramatic, but tracking down and fixing such "errors" can be maddening.

