Slashdot Mirror


Threads Considered Harmful

LBR9 writes "James Reinders compares native threads with the goto statement so famously denounced 40 years ago by Edsger Dijkstra. Paraphrasing Dijkstra, he says they both 'make a mess of a program,' and then argues in favor of a higher level of abstraction. A couple of people commenting on the post question whether or not we should be even be treading into the 'swamp of parallelism,' echoing the view recently espoused by Donald Knuth."

16 of 266 comments (clear)

  1. I disagree with both this guy AND Dijkstra by halivar · · Score: 4, Interesting

    Goto's and global variables are not inherently wrong or evil. They are tools. Granted, they are tools that, if misused, will wreak havoc on your code's stability and maintainability. The same could be said, however, for pointers. Threads are dangerous, and require special care. This is not a reason to avoid them; it is only a reason to be incredibly careful with them.

    Use the best tool for the job, regardless of whether your CS professors demonized it or not.

    1. Re:I disagree with both this guy AND Dijkstra by Chandon+Seldon · · Score: 2, Interesting

      If you don't think that we should be using hardware advances to make things easier on programmers, then why do you use compilers? Compared to hand-tuned machine code specific to each target processor, the stuff that comes out of a C compiler is slower by a factor of 2 to 10 at least. Other languages even more so.

      The fact of the matter is that high level tools are almost always the right choice, and the standard rules of optimization apply:

      Rules of Optimization:
      1. Don't do it.
      2. (experts only) Don't do it yet.

      With concurrent code that's just as true as it ever was. If you can use an abstraction that makes thing easier to understand, you'll get the project finished on time and stable. On time and stable trumps 3% faster with deadlocks a year late *every single time*.

      --
      -- The act of censorship is always worse than whatever is being censored. Always.
  2. Hmm by LizardKing · · Score: 2, Interesting

    The problem is not threads per se, but the way they are generally used in programming languages like C and C++. Although const correctness is understood by some C++ programmers, they appear to be a minority if I judge by the code I regularly review. There is also memory management which is a much bigger issue in threaded C/C++ applications than in applications written in Java. The Java library provides good examples of immutable classes, most prominently the String class, that remove a number of problems often encountered with their mutable cousins like std::string. Unlike std::string, I don't have to remember to make it immutable by constifying it or wrapping it. The presence of immutable classes, and the more adequate coverage given them along with threading in Java textbooks means that I disagree with the articles' author who lumps Java threads in with pthreads as a bad thing. What we need is more coverage of threading issues and how to alleviate them in intermediate level C/C++ textbooks, because despite the fact that threading is not built into those languages or their standard libraries, concurrency has become too important to ignore once you go beyond the basics.

    1. Re:Hmm by Max+Threshold · · Score: 2, Interesting

      Yeah. The main problem I've seen is that many developers apparently don't understand event-driven programming at all, so they end up creating dozens of threads to poll for various conditions, and then usually fail to come up with a thread-safe way of coordinating the whole mess. Threads aren't the problem; applications will always use threads, even if it's not explicit. Incompetent developers are the problem.

  3. processes by mkcmkc · · Score: 3, Interesting

    Well, for starters, there's processes, which were invented in the 1960s. These may not handle every case, but in my experience they'd cover 95+%...

    --
    "Not an actor, but he plays one on TV."
  4. "Threads" are not the problem. by jythie · · Score: 2, Interesting

    The problem is that programmers are generally untrained in them or trained very poorly.

    Writing a safe threaded application is not a difficult task, but it is a different task then writing a single-threaded app. And unfortunately CS programs, books, tutorials, etc, still train people in the single-thread mindset and yes the programs they produce end up being buggy.

    And I'm not sure these 'high abstraction' languages are really the 'answer'. I have found that often in higher level solutions the results become even less predictable and tracing what is actually happening when becomes either extremely difficult, extremely inefficient, or just back to the single-thread mentality.

    I think the OP talking about how one might be next writing a parrell app shows the real flaw here... the author is going from one mentality, entering another without really thinking it through, and then complaining when old methods don't work well. Take a programmer who STARTED in parrell space and you don't run into these problems.

  5. Re:How about "C++ threads considered harmful"? by Arslan+ibn+Da'ud · · Score: 2, Interesting

    The problem with Java concurrency and threading is, all the locks are advisory. The synchronize statement is a nice bit of syntax, and making it apply to whole blocks of code was the Right Thing to do.

    The problem simply comes in that a program is not obligated to *use* synchronize, or any locking, when it accesses objects. Which means the code is totally unsuitable for integrating into a multithreaded program. And trying to backport thread-safety in is (currently) too difficult, as there are no tools to tell you when you've got it right.

    I haven't studied Erlang yet, but threads (or more generally concurrency) done securely would require mandatory locking of all data..except when you know two threads must share data and sync between each other. Ada95 seems to understand this, although it probably needs refinement.

    Which makes threads functionally equivalent to UNIX processes & shared memory :)

    --

    Practice Kind Randomness and Beautiful Acts of Nonsense.

  6. Right. Mod parent up. by Animats · · Score: 2, Interesting

    The problem is not threads per se, but the way they are generally used in programming languages like C and C++

    Right. C and C++ provide zero help in dealing with the isolation issues of threading. The languages have no concept of parallelism (there's "volatile", but that's about it.) There were 1980s languages that did offer some help, such as Modula I/II/III, Ada, and Occam. Java has some minimal concurrency support, although it's not well thought out.

    There's nothing wrong with multithreaded programming, but some help from the language would be nice. Major issues with threads are "which thread owns what", "which locks lock what data", and "what can I safely call concurrently". C and C++ do not help here. They push the problem off to the operating system, which has no idea what to do about thread level data ownership.

    At the operating system level, we're not doing too well either. One good way to write concurrent programs is with multiple intercommunicating processes. Unfortunately, the Unix/POSIX/Linux mechanisms for interprocess communication are awful. You have byte-oriented pipes, sockets, and the seldom used "system V IPC" mechanism. None of these let you do something like an inter-process subroutine call. Subroutine call mechanisms built on top of these stream-like channels tend to be slow, clunky things like CORBA and SOAP. Windows does a bit better, but their fast approach is a legacy from OLE, which was designed for Windows 3.1 on DOS, and their slower approachs are more like SOAP. QNX has usable interprocess messaging, but few non-real-time systems are designed for QNX.

    I've been writing heavily concurrent programs with threads since the 1970s. It's possible to do it well, but the tools have not improved much.

  7. Re:How about "C++ threads considered harmful"? by Jellybob · · Score: 2, Interesting

    I haven't studied Erlang yet, but threads (or more generally concurrency) done securely would require mandatory locking of all data.


    I may have misunderstood (I'm not exactly an expert in threading), but I believe that Erlang handles this is a scarily elegant manner... once assigned, a variable can not be changed.

    The = operator in Erlang should be looked at in the mathematical sense, so the following (pseudo) code would fail:

    a = 2
    a = 1 + 3

    Because 1+3 != 2

    (Disclaimer: I've briefly dabbled in Erlang, but anything I say about it should be taken with several rocks of salt)
  8. Threads work fine by mugnyte · · Score: 2, Interesting
    Going beyond what you state - indeed I agree: Threads have a useful place in the toolbox. Perhaps this will mark me as "old" at some point in the world of programming.

      I use them routinely on MS platforms. Background threads for write-behind mechanisms, for self-tuning caches, for animation. The sharing between threads is the more-precise problem, not threads itself. If one knows how to examine the context of a thread, one can see all shared pints and code accordingly. This is no different that knowing what pieces of data are eventually exposed as public data of a component.

      That said, there is a clumsy set of constructs around threading still. Most modern languages do not have the atomic test-and-flip operation around an object as you wish. For example, in the C# realm, I see this routinely:

    if ( !sharedMemInitialized ) {
        lock( sem ) {
          if ( !sharedMemInitialized ) { // awkward
     
    // ...................initialize
    ...I'd much more appreciate the OS supporting a thread-level operation that allowed for

    sem.LockIf( !sharedMemInitialized ) {
     
    //................ initialize
      }
    ..where above clause was skipped if (sharedMemInitialized==true), and if not, it waited for the "sem" semaphore concept to be unlatched.

  9. Re:How about "C++ threads considered harmful"? by larry+bagina · · Score: 2, Interesting

    In Erlang, variables aren't variable -- they're single assignment. (There is a process dictionary that is mutable, but it isn't usually used and other threads don't have access to it). Inter-thread communication is done via message passing (which may be local or over tcp/ip).

    --
    Do you even lift?

    These aren't the 'roids you're looking for.

  10. Re:Some people can handle threads... by everphilski · · Score: 2, Interesting

    I'm an aerospace engineer, but write code 40-60% of my workday. Essentially between a FORTRAN/C++ compiler and Excel, those are my design tools. In the last 4 years (I'm relatively fresh out of college), I've used GOTO once. And you are right, it's a useful tool in very specific situations, in FORTRAN. However in C++ with object-oriented programming, I have yet to see a case, in the work I do anyways, where it would make something more concise.

  11. The Actor model is the solution by master_p · · Score: 2, Interesting

    The Actor model, where each object is a separate thread, is the way to the future. When an actor sends a message to another actor, the message is stored in the target actor's message queue and the thread that represents the target actor is woken up to process the message. Results are delivered with future values.

    With the Actor model, whatever data parallelization is there in a program is automatically exposed.

  12. Re:I'm All For Getting Rid Of Threads, But... by Cheesey · · Score: 2, Interesting

    It's very unfashionable, but the Ada language has threads (tasks) as a first-order part of the language, so you don't need a specific class or library in order to use them. The things you need to use threads safely, like protected objects, are also part of the language. That means it is very easy to write correct multithreaded code in Ada. You won't be missing a mutex unlock command, and you won't be accessing something owned by another thread: the compiler won't let you.

    Threads are one thing that Ada does really well. I don't know of any other language in the ALGOL family that matches it. Certainly C/C++/Java are far behind.

    --
    >north
    You're an immobile computer, remember?
  13. Re:Except ... by Fry-kun · · Score: 2, Interesting

    Who was it that said that "Computer Science" was the worst thing to happen to both computers and science?

    Right now, everyone thinks in terms of Turing Machines - we tell the computer what to do. In functional programming, you tell the computer what result you want to achieve (in terms of formulas and such) - and it does it for you.

    It's hard to grasp for someone who's used to the Turing way, but it's not for someone who hasn't dealt with it. Programmer should be able to give hints to the CPU (for optimization, etc.), but not detailed instructions as we do now.

    --
    Did you know that "FTW" ("for the win") is a direct translation of "Sieg Heil"?
  14. Fancy programming languages are NOT the solution. by ulatekh · · Score: 4, Interesting

    I'm tired of reading replies to this article that evangelize some fancy-schmancy high-level solution. I wonder if these advocates have ever tried writing production code in such an environment.

    Let me give you a wonderful example of when theory simply doesn't meet reality.

    Recently, I wrote a bunch of multi-threaded code for a next-generation asymmetric-multiprocessing game console that shall remain nameless. Its operating system has a wonderful complement of synchronization features. There's the usual mutex lock/unlock, and the usual condition signal/wait, but there are also event queues (queues of generic events that can be passed between threads running on different types of processors), lightweight mutexes/conditions, spinlocks, semaphores, reader/writer locks, and so on and so on. Truly a rich palette from which one can paint a wonderfully synchronized multi-threaded application! I then proceeded to try to rewrite a key section of our code in a very multi-threaded way.

    The problem was, the first version of this code added NINETY milliseconds per frame to our main thread. A profile showed that nearly all of the extra time was spent in the operating system's synchronization features.

    After much rewriting and much pain, I stopped using all of the operating system's synchronization features, and used processor-level atomic operations instead, and finally, the extra code accounted for only FOUR milliseconds per frame in our main thread (with the rest of the time successfully farmed out to separate threads).

    I challenge anyone with a fancy-schmancy automatic concurrency solution to demonstrate that it doesn't have this problem.

    --
    "Once we've identified and embraced our sickness, we'll have strength...and that's when we get dangerous." - John Waters