Updated: Thanks to Captain Bedsock, link is restored.
I’m reading this post on the C++ committee’s dealings on threading, and, I am pleased to announce, there is absolutely no chance what so ever of anything sane, workable, or sensible accidentally arising from these precedings. That’s saracasm, but not by much. By the very nature of their responses, most of the people participating in this design meeting had no experience what so ever with multithreaded programs, and the problems that accompany them. Worse yet, they display a gross ignorance of compiler construction and optimization. Just who you want defining what is inarguably the most tricky aspect of an imperitive language (as the Java people found out the hard way).
Let’s start with Hans Boehm’s “surprising” example. You have two differnet variables, x and y, both starting out as 0. Thread 1 executes the code “x = 1; r1 = y;”, while thread 2 executes the code “y = 1; r2 = x;”. Is it possible for both r1 and r2 to get assigned 0? Yes. Duh! It’s called load lifting, a special case of strength reduction. It’s an important optimization these days because of the long times that loads can take- and the fact that the values can not be used until the load completes. Stores can take forever and no one cares, but waiting for a load can stop a program dead in it’s tracks. So the sooner the load can be started, the less cost the load takes.
This is the problem with multithreaded imperitive code, well, one of the problems anyways. This sort of optimization is impossible to detect in single threaded code- so programmers could conviently ignore it (except that their programs ran faster). But in multithreaded code, such optimizations become visible. The response to this “revelation” is as predictable as it is stupid:
The ordering rules may be logical, but in this case, the result came as a bit of a shock to everyone, especially Herb who felt this was far too dangerous. Won’t unsuspecting programmers expect such a straightforward use of atomics to be fully ordered? Most of the room agreed, and Hans has since altered his proposal so that the conversions between
atomicandTare fully ordered. You may lose some performance, but you get to keep your sanity, and the lower-levelloadandstoreare still there for all the insane hacker-types out there.
“Don’t optimize my code!” in other words. “I want it to run slower than molasses in January!” This seems to be a standard response of many programmers when they discover the compiler actually optimizes their code. The correctness of the resulting code is totally irrelevent- that the compiler dares change their beautiful code in the least way is an unforgivable transgression.
Hans’ “low level” definition is, in fact, anything but. Actually, it is low level, but only in the bad ways. Consider for a moment what an implementation of this proposal would look like on, say, the x86 architecture. The committee members seem to think that having, say, atomic would optimize down to normal int loads and stores. The problem with that is that there is no way to prevent race conditions with the standard integer loads and stores. So the only implementation I can see is that the compiler would quietly add a mutex (or at least a spin lock) to every atomic value, which is locked when load() is called, and released when store() is called.
This prevents race conditions (at least with atomic data- programmers are still allowed to screw up and introduce race conditions with non-atomic data), but at the cost of introducing hidden deadlocks among the implicit mutexes used to wrap atomic types. On the PowerPC, you might be tempted to implement the atomic types with the load locked/store conditional instructions- but this would be wrong. Consider the code
t1 = x,load();
printf “Foo!\n”;
x.store(t+1);
How often can the above code print “Foo!”? No, even on the PPC, atomic data types would have to be implemented with mutexes. Oh, and no mention of what happens if you forget to release an atomic variable you’ve acquired.
Herb’s proposal sounds somewhat less foolish- in fact, it’s probably the one I’d pick were I required to design a memory model for C++. It’s basically the Posix threads model roled into the standard- probably not a bad idea. Unfortunately, the straw poll results show where the committee is heading- adopting both. This is the fundamental problem of design by comittee. Especially a committee that obviously has so little knowledge of the problem domain.
That ignorance was on display again with the debate of what “volatile” means. Obviously, knowledge of the relevent specifications, especially the 1989 ANSI C standard, is not a prerequisite to be on the C++ standards committee. I know this because the 1989 ANSI C standard explains what volatile means. I shouldn’t be surprised by this, since knowledge of the 1989 ANSI C Standard wasn’t even required to be on the 1999 ANSI C Standard committee (see long long).
Another standard (pun not intended) problem the C++ language design comittee seems to have is a fasincination of form over substance. How new code looks is more important than how it behaves. Lots of tricky implementation details can be swept under the rug if the new code looks cool. So Lawrence Crowl’s suggestion of implementing the join calculus (not a bad idea, IMHO) has met with opposition. It didn’t look cool. But that neat way to upgrade a reader lock to a writer lock using a move constructor- now that was cool. Never mind the niggling little implementation details. Like if you have two threads, both holding a reader lock on an object and both trying to upgrade the lock to a writer lock, what happens? But, but, but- it uses a move constructor! How can you not like it? Um, yeah. Reader-writer locks are one step up from stone knives and bear skins (aka spinlocks). Of course, the only nit they could find to pick was with his spelling.
My critique about the Crowl’s idea’s reception may sound somewhat bitter, until you realize that Kevlin Henney proposed effectively the exact same idea- the join calculus. Except that he replaced “int join pending” with “joiner wait_for_value”. And we all know how cool templates are- they define cool. And they look real neat . So rather than the brush off that Crowl received, Henney had a warm reception. Note that they did not tell Crowl “Neat idea- but can you make it a library, maybe using templates, instead of keywords in the language?” No, Crowl’s idea was bad, Hennley’s was good. Since they were effectively the same idea, it has to be the form the idea was presented in, not the substance, which was the basis for the decision. And no one even mentioned the real problem with the idea, in either form. The problem with the join calculus in an imperitive language is that it makes synchronization issues, especially race conditions, an even bigger problem then when threads are relatively rare. What happens if a thread tries to get it’s own return value? Etc.
The cherry on top of the whole proceedings comes at the end. I quote:
As Beman Dawes correctly observed to me over lunch, the group really would be in bad shape without Hans’ encyclopedic knowledge of threading issues.
In other words, only one person on the committee had signifigant knowledge of, or experience with, the problem domain. And that this was obvious to at least two observers. Although I wonder if Crowl and Henney might not have more experience and knowledge than they’re letting on to.
I would be the first to admit that this problem is exceptionally difficult and tricky, with large numbers of hidden pitfalls. I have my fare share of scars from falling into them often enough. But there’s nothing like adding a hat full of ignorance to make a hard problem impossible- and this committe has ignorance enough for three. As such, the odds of anything implementable and usable, let alone sane and usefull, comming out of this group has to be about zero.
No related posts.
Pingback: Social Content Headline News
Pingback: Thoughts Made Words
Pingback: Enfranchised Mind » What the heck…?
Pingback: The Cheap Sitcom Clip Scene Blog Post | Enfranchised Mind
Pingback: The Blog’s Most Popular Posts | Enfranchised Mind