Slashdot is powered by your submissions, so send in your scoop

 



Forgot your password?
typodupeerror
×
News

What Debugger Is Best For Multithreaded Apps? 257

pollyp asks: "I'm on a team that's working on a multi-threaded (pthreads) C++ application running on GNU/Debian 2.2. One of the challenges of this project is trying to debug the app, or making sense of core files; the feeling is that gdb is just too difficult to work with in a heavily threaded app. We're looking for better tools, and if that means changing languages or going to another UN*X, we're ready to do it. So what is the best, most mature OS/language/tool UN*X environment for doing multi-threaded application development on Intel?"

"One part of the team wants to stay on GNU/Linux but use Java. Java's performance is becoming less and less of an issue, and the GNU/Linux development tools are reasonably attractive (e.g., Visual Age's debugger). The other part of the team wants to stick with C++, but move over to Solaris. But none of us have any practical experience with Solaris, nor do any of us have a sense of how fully baked their Intel development environment is."

This discussion has been archived. No new comments can be posted.

What Debugger Can You Use For Multithreaded Apps?

Comments Filter:
  • by Anonymous Coward
    Why change views when you change from editor to debugger and back like older tool chains force you to do? In Paradigm C++, the editor and the debugger are the same view. A click lets you edit code, another click lets you rebuild your application and you have never left the position of your code to make the change and confirmed the correction. This is the most time-efficient method of debugging.

    You can start a debugging session by double clicking the .AXE node in the Project window. Once in a debugging session, the Edit window local menu (right-click in window) and Speedbuttons under the Menu bar display debugging commands. The Load command under the Debug menu will load a .AXE file on the target and start a debugging session if you don't have a project file.

    You can build your application in real or protected mode. Choosing a Target platform is as easy as right-clicking the .AXE node in the Project window, selecting TargetExpert and choosing a target type. You can even run a protected mode application without a remote target system and test your code right on the PC. This can be done by choosing Win32 emulation as your Target Model in TargetExpert. Memory models can also be changed in this dialog.

    Paradigm C++ even has the smarts to inspect an object by simply passing the mouse cursor over it in the Edit Window. Since it also knows the debug symbols in the current scope, you always have access to the most frequently used debug information without any additional effort.

    During debugging, the editor view includes local menus containing debugging options such as Inspect or Watch. Source lines with debugging information are marked with red dots and the current execution point and enabled/disabled breakpoints are all marked.

    You can open a CPU view to see the actual code created by the compiler or assembler or see register contents. This window handles viewing of memory, registers, processor flags, and stack and includes options to help you checkout low-level code. You can bring up the CPU view at the current CS:IP by using the View menu command. Or to bring up the CPU view corresponding to any source line, use theView CPU command from the Edit view local menu.
  • by Anonymous Coward
    Why do I have the feeling that the article and this comment were posted by the same person plugging their software?

    I mean 10 minutes after the article was posted we get this 6 paragraph commercial posted by an AC. Don't mean to sound bitchy, Paradigm C++ could be good and I might give it a try when/if I develop in C++ again, but at least you should try being more honest about what you are doing...
  • by Anonymous Coward

    The gnu visual debugger [act-europe.fr] is based on gdb, and claims to have much-improved support for multithreaded code. I haven't used it myself, though.

    If you're considering a different language, Ada is worth a look. Gnat [gnuada.org] is a complete and stable compiler in a way that g++ is not, and the language was designed for multithreading from the start.

  • ...and be aware that there are many, many bugs in Solaris' threading libraries.
  • by Bongo ( 13261 ) on Saturday December 16, 2000 @03:46AM (#554681)

    So what is the best ... tool ... for doing ... application development?

    16 cups of this [lavazza.it].

  • by Kieckerjan ( 38971 ) on Saturday December 16, 2000 @03:50AM (#554682)
    Given the fact that 90% of all C / C++ bugs are caused by memory related issues (buffer overruns and memleaks being the most notorious ones) it would probably be a wise choice to move to Java, if you don't mind the (minor) performance hit. My own experience is that when writing Java code you spend a lot less time in the debugger, because (a) the garbage collector prevents memleaks (b) buffer overflows generate very clear error messages instead of a stupid core dump. So the choice of debugger automatically becomes much less of a issue.

    As to performance: if you're not writing a nuclear explosion simulator, Java's performance is probably adequate. (Think StarOffice here.)
    --

  • by SLOGEN ( 165834 ) on Saturday December 16, 2000 @03:53AM (#554683) Homepage

    Are you really changing Language and OS for better multi-thread debug?

    This is one of the symptomathics of IT today. You start out analyzing the problem, then you choose an aproprite tool. Some month's later you hit trouble and you consider moving to new language, OS, architecture, whatever, totally discarding the initial analysis that led to the choises you made!

    On topic: You should not expect multi-threaded code to be easily debugged, afterall it is hard to write!

    You should instead put effort into the really core components that are multi-threading sensitive (synchronization when referencing datastructures and stuff like that, btw. C++ is excellent for that, using Monitors), and make all other code REQUIRE to use the methodology you develop in these components.

    Try to collect the multi-thread sensitivity in small, well-defined areas of your program, and try to prove, or at least reason, about the correctness of the code there. One thing you may wan't to do is define (in C++) Locking Iterators, which Lock datastructures they work on, and (using reference counts) automatically unlocks the structure when Iterators fall out of scope.

    You may also have some luck in using some of the design patterns that deal with multi-threading.

    Morale:You cannot debug away every race-condition, that's bad practice you HAVE to think.

  • by Faré ( 6486 ) on Saturday December 16, 2000 @04:00AM (#554684) Homepage
    Functional programming languages will provide you with great tools that will avoid most sources of core-dumping:
    • OCaml [inria.fr] is multithreaded (linuxthreads was born as a way to get it to work on linux), although a single program won't take advantage of a multiprocessor. Core dump is impossible using its static strong typing, and the optimizing native-code compiler provides with great performance.
    • JOCaml [inria.fr] is an extension of OCaml based on the Join-Calculus, the latest and greatest paradigm for distributed programming (can be seen as actor-based programming done right, as based on a well-understood algebra). Can take advantage not only of multiprocessors, but of processor farms, or any distributed architecture, even heterogeneous architectures. Only bytecode can migrate, native code modules and primitives must be compiled into the servers.
    • Erlang [erlang.org] is based on a paradigm quite similar to jocaml, but is designed for industrial applicability rather than hacker coolness; it has dynamic typing, a pure functional core (despite the logic programming syntax, it only has matching, not unification), enriched with explicit asynchronous communication primitives, and an implementation that every phone call you make depends on, if you use British Telecom. If you need tens of thousands of threads and/or lots of nodes, this is what you need.
    • There is also Mozart [mozart-oz.org], an distributed implementation of Oz, a real logic programming language (has unification).
    • Haskell [haskell.org] and Mercury [mu.oz.au] also have extensions for concurrent and distributed programming in the works, but I admit I don't know how usable they are for real programming.
    Use real languages with a nicely designed concurrent programming algebra, not fake languages that were never designed to begin with, and had a kluge of concurrent primitives added by drunk people without a clue. Forget core dumps. Catch exceptions and receive exit messages instead.

    -- Faré @ TUNES [tunes.org].org

  • by Anonymous Coward
    I would strongly suggest you consider Ada 95. From a concurrency perspective it is extremely good. You'll probably find that you introduce fewer bugs in the first place because the syntax for tasks is nice and clear.

    As for debuggers, I've used DDD (a gdb frontend) but never with threads. I tend to just use the old trick of sticking a few printf statements in key places.


  • I think that too. The company would have actually answered the question (and said something about threading, which is totally absent in the Paradigm post)

    The few lowlevel workarounds that are included (single handedly setting cs:ip), can be done in GDB too afaik.
  • by Anonymous Coward on Saturday December 16, 2000 @04:12AM (#554687)
    As far as debugging is considered I would recommend DDD. It is a visual frontend to various language debuggers including C++. And it does provide access to threads of a process. So although it does not replace gdb, it may make using it easier for you.

    I would also suggest using a thread class that encapsulates the pthreads interface. I have a system in production that uses the omniThreads thread library. omniThreads is part of the omniORB library, but it compiles stand alone without any ORB related stuff. (FYI: I compiled it as a shared library ) It is very portable across machines (may help when switching to another machine)

    Writing threaded programs is very easy in Java. However, my apps have been simple enough that I have not had to debug the threaded application. If your application is a server app, with not so realtime requirements, you may want to try java. If it is a GUI app, you probably should not !!

  • I think that is a pretty severe performance hit.

    I would rather use the Ada as suggested before.


  • In the true open source mind, it would be better to say:

    You are changing a debugger because it misses a feature? THEN IMPLEMENT IT

    I'm sure the GDB team is curiously awaiting your patches.

    You can CVS the GDB source up to date every day.
    (I use a gdb from the devel branch, because it compiles easier on FreeBSD)
  • Good on you, SLOGEN. The most sensible technical response-post I've seen on /. in an age.
  • I think more often than not it's the first step that's skipped. So many company do so little pre-planing. If more people took the time to analyze their problem and choose the correct arch/language there would be far fewer switches occuring. Choose the right tool for the job BEFORE you start, don't lock yourself into somehting just because it's there.
  • If you're trying to track down memory leaks/overruns/general corruption in C or C++, even in multi-threaded apps, I've found Insure++ from Parasoft [parasoft.com] extremely helpful. It even tracks corruption on your stack (something I couldn't find in any other piece of software for x86/Linux)
  • by gormanly ( 134067 ) on Saturday December 16, 2000 @04:25AM (#554693)
    Well, I do parallel F90 development, and the only debugger worth the name that I've come across is Totalview [etnus.com] from Etnus. Supports C++ on Linux and the tech support's pretty good. Free trial version too.
  • by MichaelJ ( 140077 ) on Saturday December 16, 2000 @04:26AM (#554694)
    I used Solaris (on Sparc, though) quite extensively for multithreaded development using their SunPro Workshop (4.x) environment. A very well-done IDE that integrates directly with Emacs, your own Makefiles, and overall can be as much or as little visual vs. command-line as you'd like.

    The debugger is dbx, fully supporting multithreaded debugging, and has a full GUI on top of it, as well as full visual integration into Emacs (better than you've ever seen gdb do).

    Some people think that Solaris' thread libraries are less than adequate. Personally, I've never used a better multithreading system. The entire "kernel-scheduled LWP managing user-scheduled threads" many-many concept is more efficient and works far better than Linux's one-one kernel-scheduled threads. And all your threads run with the same PID - what a concept!

    The obvious disclaimers are that I haven't used the newest Solaris tools, nor was this done on x86, but definitely consider not only the tool quality but also the OS' attitude towards threads. Solaris is better than Linux in that regard, IMO.

    Michael J.

  • GVD [act-europe.fr], the GNU Visual Debugger, is a graphical frontend for your favorite debugger (it comes with GDB support, but you can add other debuggers pretty easily, too). Written in Ada to debug Ada programs (where multitasking support have been part of the programming language for ages), GVD presents multiple threads of control in a usable manner. However, GVD is still quite young, so there might be some rough edges.

    On the other hand, I've experienced that LinuxThreads (the thread implementation provided by GNU libc) and GDB don't mix too well. Maybe you can try another pthreads implementation, for example the one from Florida State University (FSU Threads).

  • Threads are notariously hard to debug. Linux threads have been in my experience especially hard. Make sure your using the latest kernel as there are some problems with the If you think about it, how would one debug a highly threaded application? What would you do with something that had 20+ threads? I can just imagine a programmer sitting there switching between terminal...
  • Solaris has very evolved tools. My company does development on Solaris then ports to other platforms. Solaris's dbx is _rock solid_ for mthread apps. Also you have pstack and truss (ie strace for linux). Purify runs on Solaris too. Also you can get vsar, the most amazing tool ever invented. It enapsulates everything in sar but in a vt100 interface so you can monitor _everything_ realtime. I don't know if Solaris x86 is as nice as Solaric Sparc.
  • I've been usign GVD for a couple of weeks and works well with multithreaded programs:

    http://www.act-europe.fr/gvd" [act-europe.fr]

    And it also supports native and cross debuggers (VxWorks, LynxOS, JVM, ...), remote launching of debuggers, different languages, etc.

    --
    To visit or not to visit: findusclub.com [findusclub.com]

  • The best debugger is your brain analyzing the observable behaviour of the code. Read it, study it. Fix the bugs based on that. With a debugger, you tend to fix symptoms, not the disease. Anything else is second best at best.

    Almost all of the Linux kernel was debugged that way.
  • by japer ( 87553 ) on Saturday December 16, 2000 @04:46AM (#554701) Homepage
    Actually, it is a misconception that java doesn't suffer from memory leaks. Just because it is garbage collected doesn't mean that you don't have huge trees of objects that will never get gc'd. If you don't explicitly design in creation/destruction of your objects you will leak memory. For the average sized application it propably isn't noticeable, but if your app needs to run for a long time, you will eventually run out of heap.
  • but Irix has a couple of really handy debugging utilities, Purify and TotalView Debugger. I haven't used Purify much, but TotalView is incredibly handy.
    -fnord

  • by heikkile ( 111814 ) on Saturday December 16, 2000 @04:57AM (#554705)
    Firstly, multithreaded stuff is hard to write, and harder to debug. No fancy tool will get you around that. Changing to new languages, tool, and environments usually screws up the first project or two, and it sounds like your project does not need another reason for things to go wrong.

    I can not know much of your situation, but on the surface it looks like a perfect example of the need of a clean rewrite. Scrap all the code you have, and the whole design, and consider all of it at most a preliminary study. But for crying alound, keep the same people and the same tools, unless it is blindingly obvious you are trying to use a totally wrong tool for the job - and C++ for multithreaded programming is not such a bad choice. If need be you may have to add one or two good, experienced people in your team.

    Then, start from the beginning. Design the system all again. You know you have problems with thread, so do not overuse them. Consider each thread a black box, and specify its interfaces, just like you are supposed to do with single-threaded systems. Specify the lockings and controls you need for things to work. Then implement bottom up, and test everything as you go.

    Spend more time in designing end implementing test suites than on the project itself - this will cost more at the onset, but increases your chances of getting the job done, probably faster than without the investment.Build a good debugging log that can be written from any thread, and where you control bufering. Build test routines to delay things, and pepper your code with them. Routines to exercise each module independently, and various combinations. And what ever else you can think of, that might come in handy. Make most tests automatic, so you can leave them running every night if need be. But most of all, make a clean and understandable design, and do not introduce new languages, tools, methods, or any other reasons for confusion!

  • Your options (?) essentially consist of two tools: DDD (http://www.gnu.org/software/ddd/) and GDB 5.0 (http://sources.redhat.com/gdb/)

    I wouldn't go with the latest beta version of DDD, but use the latest release version. You *must* use GBD 5.0 in order to get a hope to work with threads.
  • to make this stupid suggestion..

    1. What the hell has this got to do with his suggestion - he's asking about debugging threads. It would have made some sense if you had talked about threads in Java and the tools provided to debug them (for instance JbuilderX allows thread debugging, but it's far from ideal). Java threads are notoriously error prone same as threads everywhere.

    2. "Given the fact that 90% of all C / C++ bugs.."
    This is a fact that you pulled out of your ass. It may be roughly true for novices or students, but is nonsense for experienced developers. With tools like purify, these problems are very easy to track down in C/C++, and 2nd nature to avoid.
    Java encourages people to forget about these problems and rely on gc, then they leave dangling references dotted around and wonder why their disk is grinding.

    3. The performance hit is not minor. Sometimes, in simple cases, Java works great, but it depends what you're doing. An uncontrived comparison is at http://sprout.stanford.edu/uli/java_cpp.html
    In summary, with HotSpot 1.3 beta, (a JIT that Sun touted as being faster than C++ !!) Java was roughly 5 times slower than C++.

    4. Is StarOffice supposed to be an example of a good Java application with acceptable performance ? Heaven help us, it makes Word2000 seem slick and efficient.
    Are there *any* examples of serious Java applications with acceptable performance ?

  • Not sure why that is. You can get it for now at www.gnuada.org [gnuada.org], though you might have to make do with a (source) rpm.
  • I have authored some pretty intense multi-threaded network servers and find that the tools and environment offered by Sun are far and above the best. The Sun Workshop 5.0 C++ compiler and debuggers are amazing. The OS is rock solid, and the envionment is a genuine joy to work in. You can outfit your developers with Ultra-5 workstations including the compiler all for just $3000 through the end of December too. Solaris 2.6, 7, or 8 are all a good choice.
  • The best debugger is not your brain alone. Your brain, in conjunction with a multitude of tools (such as gdb, truss, gprof, assert, and debug-output) gives much better results.

    With a debugger, you tend to fix symptoms, not the disease.

    A doctor "fixes" patients by examining their symptoms, determining what their disease is, and then curing it.

    Programmers do the same thing. Merely thinking about a problem and mentally stepping through code is a piss-poor way to figure out what's going wrong. Stepping through code with a debugger is a hundred times more effective, especially in a team environment where you are debugging code you didn't write, or when a junior programmer is misusing a library routine he thinks he understands.

    While it is true that some programmers take stupid actions based on what they see from the debugger, that is because their brains are stupid -- not because they are using a debugger. The debugger is merely another tool for diagnosing a problem, and provides food for thought. Nobody has ever claimed that is a replacement for a good brain. Yeesh.

    --
  • by wocky ( 17453 ) on Saturday December 16, 2000 @05:58AM (#554720) Homepage
    In my experience using various debuggers over a number of different projects, none of them are particularly useful with multithreaded programs. Almost any of them are good enough to get stack dumps of the various threads and to print data values when an assertion fails, but they don't help much beyond that.

    The best way to get a parallel program working is discipline and understanding. Think about how the threads will interface with each other. Design those interfaces using appropriate known and proven synchronization methodologies. Adhere rigorously to those designs. If you're tempted to leave out a lock in some place, you'd better be able to prove that it can be done safely.

    If necessary, write wrappers around your synchronization primitives for better observability and controllability. For example, when the program crashes, you want to be able to see which threads are holding which locks, which are waiting for what conditions, etc. Being able to log the sequence of synchronization actions to a file and to force a replay of those actions in the same order will help in reproducing bugs that otherwise would manifest themselves only once every hundred runs.

    Have manual inspections of the code with a coworker. Play a game where either of you can propose a failing scenario and the other must explain using the code why that can't happen. If neither of you can explain why it can't happen, it probably can.

    Your basic philosophy should be that it's impossible to convince yourself of the correctness of the synchronization through testing. If you can't prove that your synchronization is right, it's most likely wrong. And if it's not wrong, it's so complicated that you'll break it later because you don't understand it.
  • There's been a lot of discussion so far about moving to Ada and other languages, and other OSes. I have a similar, but not identical problem: a program written in pure C on Linux (and Win32, via cygwin) that uses threads extensively. So far, I haven't found a debugger that'll do worth a darn at following threads. Rewriting is not an option. Got any suggestions here?
    --
  • Notice that GVD currently supports only C and Ada.

    It is supposedly designed where support for other languages can be added, so if you use C++ you may want to ask around and find out what the current status/prospect for C++ support is.

    --
  • I bet I've written more java than you.
    I spent about two years doing full time java
    development (full fledged scientific java application for Alcan). I first learned java five years ago, and have tried it on and off since then. I recommended using it in that project because the superficial impression it gives is pretty positive, and *anything* is better than using MFC. (I wish I had known about FLTK back then)

    I would not recommend Java for client side application development. If you really care I could drone on for days about why it's a bad idea. Personally I wouldn't use it on server side either, but I agree that it is pretty good for that. Sun has spent many millions of dollars putting together suitable libraries and tools to make it a good tool for server development.

    Actually, I had thought soffice was largely java because it's a misconception that's quite common and also because soffice is slow and bloated, but not as bad as I expected for a java application. I think it's largely C++ though. Please give me an example of a good, substantial Java client-side application if you believe I'm just spreading FUD.
  • I donno about switching OSes, but whatever OS you use you should definitly look at SPIN [bell-labs.com], a tool for modeling locking behaviour (and other things). It has found a large number of problems in real systems that "normal" debuggin had a hard time finding. Race conditions are hard to remove by inspection!

    As for Java vs. C++, well Java isn't a bad language, and having threading built in rather then slapped on as a bag on the side makes it nicer (pop quiz: what C++ facet operations are thread safe?). On the other hand I feel a bit limited in Java, and I miss the STL. As far as I know SPIN will help Java coders as well.

    I don't think Solaris x86 is a good idea. If you want Solaris, get a SPARC. Otherwise you are always behind the support curve, and the hardware support is far more limited then Linuxes. Besides the SPARC hardware is extreamly reliable (if not all that fast), and works great for lights-out operations.

  • by the_quark ( 101253 ) on Saturday December 16, 2000 @06:31AM (#554729) Homepage
    What you say is true, but it's not the issue. You can design the multi-threaded sensitivity properly, you can implement to the best of your ability, but, eventually, someone IS going to do the equivilant of *0 = 1, and your program is going to dump core. Even if it's just a typo. Believe me, I know, I founded the Freeamp project, and it is multithreaded to hell and back, and it has been a nightmare to get all the crash bugs out of it.

    The problem is, that, under Linux, if you load the resultant core file (from any multithreaded program) into GDB, it often dumps core. Which isn't very useful.

    The end result of this is that you can have a dual PIII-800 workstation, running the very latest in tools, with a highly trained developer, doing a friggin' binary search through the code with printfs trying to figure out where the stomped pointer is coming from.

    Believe me, you do this a few time and you're gonna start thinking that a language that does memory management for you probably wouldn't be such a bad idea, either.

    My OT rant - RedHat/Cygnus (leader of the gdb effort) needs to get this fixed. Quite frankly, it's hard to take Linux as a serious development platform when multithreaded debugging is twenty years back. Support the developers, first, and everything else will follow.

  • > I would strongly suggest you consider Ada 95.

    Be forewarned that when you first start using Ada you will find it very annoying that it actually expects you to say what you mean with respect to types. People who say they like C++ because "it has a stronger type system than C" don't know what "type system" actually means. (No famebait intended; just a warning to brace yourself for the shock if you do decide to give Ada a try.)

    However, in my experience, once you get into the habit of thinking out what you are trying to do, you will find that most of your bugs are discovered at compile time, and your ratio of Coding_Time:Debugging_Time will go way up.

    Notice this quote from the GVD home page [act-europe.fr]:
    Why we chose GtkAda instead of Gtk+... Another reason was to reduce the time we spent developing GVD. Using GtkAda and GNAT, we can decrease time to market by a factor of two to four over any other language/compiler.
    Raymond and Hoare notwithstanding (yes, I saw that /. fortune cookie yesterday), Ada is a very useful language.

    Also, another party has mentioned that Ada is designed for multithreading; I would just like to add that MT support is in the syntax of the language itself, and has been since 1983.

    --
  • The is what Kernighan & Pike say in their excellent book "The Practice of Programming." (And I agree..)

    As they say, "...we tend not to use debuggers beyond getting a stack trace or the value of a variable or two. One reason is that it is easy to get lost in the details of complicated data structures and control flow; .... It is more helpful to use the debugger to discover the state of the program when it fails, then think about how the failure could have happened. ..."

    Just my 0.02...

    R.

  • You *miss* the STL? Which part of java.util and other nifty 1.3 classes have you not looked at yet?
  • Personally, I despise IDEs because they always slow me down. I've noticed that the best programmers never seem to use them. I think putting well-chosen printf's in the code forces you to think about what you're actually writing, rather than writing a bunch of garbage and then using the debugger to bail you out.

    A lot of people think I'm crazy when I say this, but both Linus Torvalds and Gostling have said similar things.

    I've developed both ways, and there is no doubt in my mind that it takes me less time to develop when I just use printf's. But -- it does take more discipline, and that's probably why you see so many mediocre programmers slaves to the debugger and IDE.

    vi, make and printf (with the occasional grep and find) -- that's my debugging environment, and I'm known for my development speed and code quality.


    --

  • Please give a reference for where 'toy' languages have been used and have failed.
  • by mkettler ( 6309 ) on Saturday December 16, 2000 @07:19AM (#554741)
    I agree, it's quite ridiculous that this post has been moderated up. It's purely off-topic.

    I've actually USED paradigm C++, along with paradigm link and locate tools. It's for embedded application development. (ie: raw rom hanging off an x86 processor bus with no bios (you actually run where a BIOS would be), no OS, etc). The dev tools themselves run on ms-windows.

    This tool has little to do with multithreading, in fact I don't belive it contains a thread library at all. (I could be wrong, but I never saw one and it's not a listed feature) It supports real mode, and if you're x86 can do it, protected. It will target as low as 80186's and NEC v## processors.

    It also has nothing to do with UNIX. It's for people building non-pc x86 based systems that have no BIOS and no OS. It's for bare-metal embedded c++. You can't even run the IDE on UNIX, much less the target.

    They have a site at devtools.com, visit if you're bored, see how much Multithreaded Unix support they have...

    My personal opinions of this software aren't very high, but mostly because my opinion of x86 for raw-soldered embedded is pretty low. The product itself is relatively well written.
  • First off, I'll say I recommend a combination of C, Unix (any flavor will do), any compiler that is ANSI standard, your favorite editor, make, debugging statements and light gdb use. These get me farther than any IDE I've had to work with or tried to work with. Incidentally, every developer I can think of who I admire for producing absolutely brilliant code, especially quickly, tends to use the above. Just a favorite editor, whatever their language choice is, and simple tools. Remember the KISS principle.

    #1: Can you really switch your language or OS?
    At best I'm dubious as far as your suggestion of switching language or operating system. Unless your project is only at the very first stages, you have almost undoubtedly invested far too much effort to reasonably consider backing out. Why did you choose C++ and GNU/Linux in the first place? Surely more thought went into it than "we like C++" and "Linux is nifty", so go back to those decisions and sift for clues.

    #2: Why are you spending so much time in a debugger?
    You should be spending more time with your concepts, flow charts, and whatever else you came up with before you laid it all into code. Spend some time pondering what exactly you're trying to do, then go look at your code and make sure it's really doing what you want. A few well-placed debugging output statements (printf/cout/whatever), some good comments, and a clear head will get you much farther than a debugger, even the best. Debuggers absolutely cannot tell you what you're thinking.

    #3: Do you really need threads?
    Is your application specifically designed to be run on parallel systems? Is it designed to take the majority of a system's resources? Chances are you don't need threads, most programs don't. There are usually better ways to do things than multithreading. Also, writing threaded code is considerably more time-consuming than non-threaded code. Are you writing something so complex you need threads? If you haven't really evaluated this, now is the time.
    -wd
    --
    chip norkus(rl); white_dragon('net'); wd@anduril.org
    mercenary albino programmer for hire
  • by photon317 ( 208409 ) on Saturday December 16, 2000 @07:25AM (#554743)
    It worries me that you're willing to change platforms/languages/etc just to find the right debugger. If you stick to good programming practices, coredumps should happen rarely to begin with, and therefore the tradeoff is there to have a better language/os and a really hard time dealing with corefiles. Also, most good programmers, even when dealing with a serious bug causing a coredump, only use a debugger to get a backtrace... they don't really _use_ the debugger. And in many circumstances, marker statements in the source code are even simpler than using a debugger for a backtrace. In light of all these things, I could never justify changing my whole coding world arounda decision about a better debugger... something else is wrong here.

  • Someone is asking how to debug multithreaded C++ code and gets as an answer to use functional programming languages. Sorry, but how is this insightful? I've had to use functional programming languages (Scheme, Haskell) and like a lot of what I've seen, so this is no flamebait. It's good to know all kinds of programming languages and paradigms (bad word ;-)). But once a decision has been made for a certain language, it's no longer an issue to change the language. Nice list, though, I didn't know them all!
  • by segoave ( 115819 ) on Saturday December 16, 2000 @07:30AM (#554747)
    Or you could try ddd [gnu.org]
    If you need a visual dbugger. It acts like gdb, which I already love, but adds a visual edge that gdb alone doesn't have. When I am really stumped with gdb, I go to ddd.
  • YES!!! There are other programmers like me...

    I remember a C++ programmer asking me what debuggers were loaded on our HP system. I turned to him and said 'printf ... just like on all systems' and he looked at me like I had three heads. Ah ... kids these days have it soooo easy!

    Debugging code is very easy ... finding out where the problem is is very difficult. I include in all my programs, under IFDEF control of course, trace statements in each paragraphs that also include timestamps. It is amazing how using standard UNIX tool sets (grep, sort, etc) you can get tons of information from just this. In a multi-threaded program, I also dump out a thread-id I assign to each thread so individual threads can be analyzed.

    To be fair, I do use debuggers from time to time, but usually only has a last resort. I find it is much easier to add extra printfs than it is to set up conditional breakpoints and then step through code for hours.

    Using the above information, it is usually possible to narrow the issue down to a few lines of code. Time then to add some more printf's to dump values.

    One very large advantage of using vi (or emacs) and printfs is they are available on all UNIX systems and all compilers. When changing jobs, the last thing I want to do is be neck deep in a bug while trying to learn a new debugger

    I only use the 6 editor....
  • I use printf(), also, but it isn't sufficient for multi-threaded programs because of race and deadlock conditions. The printf() can change the timing enough to alter remove the race or deadlock. A nice debugger would help in those cases to tell where each thread is. Unfortunately, I haven't used one. In fact, I was in this situation earlier this week on a machine without any working debuggers. Reading through the code reasoning what was happening was the only method open to me. I love gdb and use printf() all the time, but in the end, understanding your code thoroughly is the only way you will be able to find and fix errors.
  • OK, I've used this quite a lot..
    It's unuseable with less than 128M or RAM. It's almost tolerable with 256M. It suffers from random freezes and needs to be restarted from time to time, otherwise memory consumption rises mysteriously. If you build a sizeable jar file from within Jbuilder it takes about 10 minutes - create the same jar from command line (jar -cvf) will take 20 seconds. It randomly caches class files, so you can never quite tell whether a source change has really taken effect - you can manually delete all the class files, do a full rebuild, and it will still use some cached class file from memory somewhere - misleading you into thinking that your code change didn't fix the bug. In the end we abandoned it and reverted to using jdk1.1.8 command line tools together with gnu make.

    Does anything else sping to mind ?
  • This makes a nice segue back to multithreaded debugging. Printf is a prime source of "Heisenbugs" in multithreaded code, because it causes code to be serialized behind the big printf lock. Programs with race conditions frequently work fine when printf is used for debugging. There are non-IDE, non-debugger based workarounds, of course. One I've found to work well is maintaining a per-thread debug log -- this avoids global synchronization and so tends to leave timing more or less intact. Incidentally, I couldn't agree less with your judgement on debugging tools, etc. The foregoing suggests that you have limited exposure to multithreaded code, where tools make a big difference.
  • How does an IDE slow you down? I've never understood that. What is it that is taking you so long to do? If you want to use the IDE the same way you use vi, make, and printf you can. The only difference is you press F6 instead of typing :make. And you press F7 instead of typing "ctrl-z; cd ../../../object/directory; ./a.out" or moving the mouse to a free xterm and typing "./a.out" there.

    I fail to see how your way is faster.

    In my experience, people who are slower with IDEs just haven't bothered to learn how to use them. They are the people who spend a few days playing around with VisualStudio and then give up saying "it is too complicated, it slows me down" all the while forgetting that it took them WEEKS or MONTHS to get to the level of profiency they currently have with vi and make.
  • by kriegsman ( 55737 ) on Saturday December 16, 2000 @08:21AM (#554763) Homepage
    When writing threaded code the developers must take the responsibility for understanding the threading issues and creating thread-safe code. But the right tools can help you get there more quickly and sanely.

    We've used Metrowerks CodeWarrior [metrowerks.com] to develop and debug very heavily multithreaded applications on MacOS, NT, Solaris, and Linux for about five years now; the CodeWarrior tools seem very much 'up to the job' and thread-aware. As a nice plus, CodeWarrior runs on multiple platforms (including Mac OS X now), which is a nice plus for our development, which is all multiplatform.

    We now use a diversity of compilers/IDEs/debuggers, but CodeWarrior is still a favorite, even if it's just because of the "Blood, Sweat, and Code [devdepot.com]" T-shirts.

  • by Acceleration ( 137330 ) on Saturday December 16, 2000 @08:21AM (#554764) Homepage
    Lot of good points already made.
    • Have small set of proven core threading routines.
    • Don't use threading unless it's really justified. At times, it seems right, but you can lose lots to context switches. So reducing threading can help too.
    • Can't debug this stuff to demonstrate correctness. Must THINK.

      To all this I'll add:
    • While staying in mainstream language land (which is worth a LOT), Java has great thread support. It works well. It works well on all platforms (excepting W95). You can use your OS of choice and switch at will for the most part. Linux/NT/Solaris/whatever. I use NT.
    • I like being able to use truss on Unix. It's *very* helpful in unraveling knotty problems. I have the most experience with this on Solaris. Solaris threading is good stuff.

      Java is a lot more productive than C++.
      C/C++ can be lots more runtime efficient.
    • In lots of circumstances, these efficiency gains are unimportant.
    • Usually more important to efficiency is algorithmic choices and quality of program implementation -- and few developers are worth a damn in this arena.
    • So C++/Java is usually moot point regards efficiency trade-offs, because programmers product is such slop anyway.
    • When programmer's code is good, then a small subset of the time, you're better off in C++ for runtime efficiency.
      Aside from that, you're better off in Java.

      I miss C++ (and even C) sometimes, but Java is usually a better language overall. Not hard to migrate.

      If you go with Java, take a strong look at Doug Lea's stuff.
  • Templates, my friend. I work in Java all the time and I still find it frustrating as hell that there are no templates.
  • by Sax Maniac ( 88550 ) on Saturday December 16, 2000 @08:24AM (#554767) Homepage Journal
    TotalView [etnus.com] probably does what you need. Other people have said it here, but I can add a little more info.

    It's a parallel debugger, which means that it has built-in support for manipulating groups of objects, as if they were one: threads [etnus.com] in a proceses, processes in a group, groups in a cluster, and so on. This means you don't need 20 windows to control a 20-thread app; we roll up an aggregated view into one window, commands work on the entire batch.

    And yes, we support Linux [etnus.com], as well as almost every other Unix out there. You can snag a free demo license [etnus.com] and download the bits from our website. And for those of you who like printf(), you can add them on-the-fly without recompiling. That saves time.

    Disclosure: I am a developer on TotalView, but I do "eat my own dog food"- we use it every day on itself.

  • by dubl-u ( 51156 ) <2523987012&pota,to> on Saturday December 16, 2000 @08:35AM (#554769)
    Yes and no.

    Actually, it is a misconception that java doesn't suffer from memory leaks.

    A classic memory leak is one where you have memory allocated but no longer have any way to make use of it. These kinds of errors aren't possible in a garbage collected language. Once you let go of your last pointer to something in Java (or, say, Perl) then the GC takes care of everything automatically.

    When debugging other people's C code, the most common memory leak I see is the temporary allocation of scratch space in some low-level routine without a corresponding release of the memory. This does not happen in Java.

    If you don't explicitly design in creation/destruction of your objects you will leak memory.

    Agreed. This is especially a problem with people new to OO design, where they haven't yet developed a good understanding of modular integrity. In practice, though, I find these kinds of errors much less frequent and much easier to find than classic memory leaks.
  • If you are doing hard real time where timing tolerances are really critical, neither printf or a software debugger are of any use. The printf will alter the timing the very thing that you are trying to observe. Although there are some fairly expensive solutions, I like using the parallel port and an oscilloscope. Instead of printf's, insert direct io writes to the parallel port into your program. View the output on a multichannel oscilloscope or logic analyzer. Some people find this approach incongruous with an operating system like Linux where such bare metal tactics seem at odds with the prevailing higher levels of abstraction. But timing tolerances can only be observed by direct viewing. If this is a project with actual funding, there are solutions that are less improvisational. Many logic analyzers have bus preprocessor cards that can be inserted into an empty card slot of almost every conceivable chassis type. The logic analyzer also come with software that will display the traces in nice formats for viewing. You can then see the timing relationships of both your inserted I/O writes as well as any other activity. On a modern computer, often all the other activity is too confusing so the logic analyzer can be set up to filter it out. There are also complete logic analyzers that can be inserted into a card slot. In spite of all the modern gadgets now available for real time debugging, I still occasionally find use for some of the improvised tricks I learned before such devices were for sale. Larry
  • by dubl-u ( 51156 ) <2523987012&pota,to> on Saturday December 16, 2000 @09:24AM (#554782)
    Wow! Who peed in your cheerios this morning?

    I was expecting someone to make this stupid suggestion. [...] What the hell has this got to do with his suggestion - he's asking about debugging threads. [...] This is a fact that you pulled out of your ass.

    When a developer (or team of developers) is spending a lot of time debugging and still not solving the problems, I ususally take this as a sign that there are more fundamental problems than the quality of the debugger. I've been developing serious software for 15 years in Pascal, C, Perl, C++, Objective-C, and Java, and I rarely need to us anything more than the occasional printf.

    Admittedly, developing threaded code is hard stuff, and I don't know enough about the original poster's problems to say what is going on. But it is possible that they are in over their heads, in which case it may behoove them to a) admit that they don't know enough and start again from basics, and b) they may wish to choose a language that is more forgiving of inexperienced developers.

    In that case, suggesting Java is a good idea. That's not to say that C is bad; if I am doing something speed-critical and am working with a team of crackerjack developers, then C would be my first choice.

    But if I'm doing something where maximizing CPU efficiency isn't our #1 issue, or if I'm working with developers who are less than stellar, then I lean towards Java. Why?
    • No pointer errors - Experts may not make pointer errors, but average developers sure do. With Java, there are no buffer overruns, no broken pointer arithmetic, no SEGVs. And even better nobody else making some stupid pointer error that hoses one of your data structures, making you spend days looking for a bug that isn't there.
    • No malloc errors - Java allows you to pay less attention to memory allocation. This makes classic memory leaks impossible, and subtle leaks harder. You're right that novice Java developers take longer to learn the value of reference handling than C developers, but this is mainly because Java extracts a much smaller penalty for those errors. By your logic, presumably, C++ would be even better if each time the developer left a dangling reference they received a high-voltage shock to the nipples.
    • Exception handling - It's been several years since I've used C++, so maybe the exception handling there has improved. But Java's exception handling is a good thing, making it much easier to track down errors when they do happen.
    • Multiple VMs - When I am getting some weird-ass error, it's wonderful to be able to try several different VMs on different hardware platforms. That removes all question of OS issues, endian problems, or bugs in the run-time.
    So the "maybe you should use Java" is a reasonable answer to the question, especially since the original poster specifically mentioned that they were looking at using java.

    Ergo, there was no need for you to be an asshole about it.
  • As many other posters have said wisely, switching tools midstream is a sure route to pain. Trust me, once you've made core tech decisions, stick with them! At least until you get version 1.0 out the door...

    I too don't like using gdb on the command line, but combined with DDD [gnu.org], the Data Display Debugger (works natively on pretty much any Unix, linux strain, I've seen ports to win32, etc) debugging is a much nicer experience. I don't write multitrheaded stuff being a pretty neophyte C++ programmer (eh, we all have to start somewhere :-) ), but I did notice in the online manual that it does have at least rudimentary support for threads.

    Plus it's free and doesn't require any changes to your environoment or toolchain. (Basically just install it, it defaults to using gdb as the "inferior" debugger (as opposed to dbx or any of the perl/python/java/whatever debuggers), and you type "ddd progname" instead of "gdb progname". It even has a command window to interact with gdb directly if you so wish...) Last but not least it has a cute logo. ;-)


    --

  • I'm currently building some server-side Java web applications. Since the Java Servlet stuff is inherently multi-threaded, I have indeed occasionally been reminded that multi-threaded applications are tricky.

    A few months back, we purchased a suite of tools from an outfit called Sitraka [sitraka.com] (nee KLGroup). They have three products that are part of the JProbe Suite [sitraka.com], a CPU and memory profiler [sitraka.com], a thread analysis program [sitraka.com], and a code coverage tool [sitraka.com].

    These are all good tools; when I was having some problems that I suspected were due to my less-than-perfect understanding of threading, I used their thread analysis tool under simulated load, and it immediately identfied my race condition, plus a couple more potential races I hadn't noticed yet.

    (This is a little off-topic, but I have to mention that their memory/CPU profiler is, pardon my french, fucking awesome; it is the best thing I have ever seen for visualizing the interior structure of a running program. After a day with the profiler, my Java code was substantially faster than the C it was replacing, despite having more features and being more secure.)

    Another tool I'm very pleased with is JUnit [junit.org], a unit-testing framework. If you're interested in trying out the Extreme Programming [extremeprogramming.org]-style approach to testing [extremeprogramming.org] (wherein you make automated, integrated unit tests that are run more or less continuously) then this is for you. And if you are having so many problems with bugs that you are considering changing languages, then I would strongly recommend that you do this. Good unit tests slow initial writing down a little, and save you extraordinary amounts of time and agony later.

    Oh, and run out right now and buy several copies of Code Complete [amazon.com] and Rapid Development [amazon.com] for the team. If you are having such large problems on the project, the problem is probably not with your choice of debugger. These books will help you figure out what the problem actually is, and give you all sorts of solutions.

    --

    For the record, and I don't have any financial interest in any of the things I've mentioned here; I just use 'em and like 'em.
  • You make some good points, and I over-reacted, but whenever someone mentions C++ someone says, hey - why not use java and all your problems will go away, I get a little tired of it.

    One thing though:
    "You're right that novice Java developers take longer to learn the value of reference handling than C developers, but this is mainly because Java extracts a much smaller penalty for those errors. By your logic, presumably, C++ would be even better if each time the developer left a dangling reference they received a high-voltage shock to the nipples."

    Exactly ! yes, that is an excellent idea. Having the program die horribly would probably suffice, but the high-voltage shock to the nipples would be even better. Immediate catastophic failure is a far more useful reaction to bugs during development than limping along, papering over the cracks.
  • by dubl-u ( 51156 ) <2523987012&pota,to> on Saturday December 16, 2000 @10:17AM (#554789)
    I over-reacted, but whenever someone mentions C++ someone says, hey - why not use java and all your problems will go away, I get a little tired of it.

    Me too. As far as I can tell, these are people who have never done any serious work in Java. Or if they have, then Java is the only language they've used on a serious project.

    Luckily, these people get what they deserve. Eventually they will be dumb enough to say things like this to a boss, who will be dumb enough believe them. And then when their optimistically-scheduled, poorly-scoped, under-budgeted project goes up in flames, they will get fucked with the sandpaper condoms. The smart ones learn after the first time that no tool is perfect for every job. The dumb ones, of course, talk trash about last tool and find the next perfect tool to talk about.

    Having the program die horribly would probably suffice, but the high-voltage shock to the nipples would be even better. Immediate catastophic failure is a far more useful reaction to bugs during development than limping along, papering over the cracks.

    And people call Java a bondage-and-discipline language [tuxedo.org]! Heh. Maybe we should dress this idea up in a lot of fancy talk about neuropsychology and maximizing feedback loop efficiency and see if we can get VCs to cough up a few million dollars to get us going.
  • I've run production environments with Solaris on both x86 and SPARC. I'm primarily a SysAdmin/Architect, not a developer, so take your coding cues from someone else (I program, but not heavy-duty professionally).

    Previous to Solaris 8, there were A LOT of serious bugs in Solaris x86 that caused it to be unusable for serious work. For web serving and simiar crap it was fine, but any complex app tended to expose bugs in the OS. Solaris for SPARC doesn't have these problems.

    Solaris 8 for x86 seems to have fixed most of the egregarious problems, and I would trust it to run your app. HOWEVER, x86 still seems to have random low-level (ie driver and the like) problems with certain hardware. Thus, I would seriously recommend that you DEVELOP on a SPARC box, which doesn't have these problems. That way, you can be sure that the bug you've just found is really in YOUR code, and not some obscure problem in the OS. One you have stable code, Solaris 8 for x86 is stable enough to run as your production OS.

    Both x86 and SPARC use the same codebase - thus, the system libraries and similar stuff all work equally well (or at least, have identical bugs...). However, the Hardware Abstraction Layer implementaion for x86 is of poorer quality than the one for SPARC (which makes sense, given Sun's priorities).

    Best of Luck.

    -Erik

  • by japer ( 87553 ) on Saturday December 16, 2000 @11:19AM (#554801) Homepage
    Actualy, I don't mean that the VM can't figure out if an object is dead or not. The problem arises as designers make design decisions without understnding the consequences.

    The problem arises when, from the designers point of view, the object will no longer be used, but from the VMs point of view, the object is still alive. An object that has a root parent in the reference hierarchy will not be garbage collected.

    Things I have seen that hold onto large object trees are things like, anonymous innner classes (implcit "this" reference), listeners on gui components not being removed, and static class variables holding onto objects.

    Java is a great programming language because it is easy to use thanks to all the built in stuff, but nothing is free. You generally pay for it with performance and memory usage.

    Here's an article discussing "memory leaks" in java

    http://www.devx.com/upload/free/features/javapro/1 999/06jun99/tl0699/tl0699.asp

  • Obviously you have no idea what the poster of the "Ask Slashdot" is talking about.

    He is asking for a good debugger for multi-threaded programming such as dbx on Solaris because gdb cannot handle threaded debugging. Instead you respond with an uninformative post that describes the worst way to debug multithreaded programs. printf isn't thread safe so it's use in multithreaded programming as a debugging tool is frowned upon unless you are using additional mutexes for logging (adding complexity) or you are using a thread safe print function such as OutputDebugString in the Win32 API.


    Grabel's Law
  • by Carnage4Life ( 106069 ) on Saturday December 16, 2000 @11:39AM (#554813) Homepage Journal
    In the true open source mind, it would be be better to say:
    You are changing a debugger because it misses a feature? THEN IMPLEMENT IT


    Comments like this make me wonder exactly whether Slashdot is read by programmers or simply people who have heard about programming and think it's cool. Multithreaded applications are hard to design correctly and difficult to debug from an application writer's point of view. Your simplistic statements belie the fact that you must be an inexperienced programmer because in the real world people don't have time to start om mammoth projects simply to help with a medium sized one. Adding threading support to gdb is more difficult than writing a multithreaded application that uses the pthread library unless the application is very complex like a compiler, relational database management system or a web browser.

    Your comment is like telling someone to hack garbage collection into C when they complain about memory leaks instead of simply pointing the person to Purify or BoundsChecker.


    Grabel's Law
    1. Java has NO! parametrised types This means that generic programming is impossible. One specific consequence of that is, that collections cannot be type-safe, and you loose a lot of the help that type-errors can buy you.
    2. Java doesn't have "const" (and friends) which means that when you give someone an object reference you have no control over what they do with that. When returning read-only object, the only solution is to clone() them. Very expensive!

    Could you be a little more specific when you say that collections can't be type-safe? Are you referring to putting several different instances of different objects into a collection and then being able to weed out the different instances by object type? I've done that in Java. It's really easy if they all implement the same interface. Once can iterate through the collection and call the same method for totally different objects. Also according to this page [sun.com], one can create constants in Java. Or are you referring to defining parameters to methods as const so that the compiler won't let you modify them? I will admit that having to have wrapper classes for the primitive types is a pain.

  • Things I have seen that hold onto large object trees are things like, anonymous innner classes (implcit "this" reference), listeners on gui components not being removed, and static class variables holding onto objects.
    While you are correct about many designers making poor design designs that affect garbage collection, anonymous inner classes are not an example. The implicit this reference you refer to is from the inner class, not to the inner class. Better examples are one-shot listeners that are never removed, and never nulling out unused private variables. The other issue with Java is that is does not know when to deallocate memory from it's heap. This can be a serious problem if you expect to hit memory load ever, even if it is a small percentage of the time the process is left running. Anm
  • http://www.devx.com/upload/free/features/javapro/1 999/06jun99/tl0699/tl0699.asp
    That link didn't work for me, but here's another article on the same topic, at Java Report magazine's site: here [javareport.com]

    BdosError

  • Use processes instead of threads in as many places as make sense. This makes many of your problems simply vanish. It makes you rethink your design in a much more thorough and thoughtful fashion, choosing distinct parts with obvious interfaces.
  • by dubl-u ( 51156 ) <2523987012&pota,to> on Saturday December 16, 2000 @01:17PM (#554831)
    Really, I agree with many of your points in the abstract. As a language for top-tier, ass-kicking developers who are wise, subtle, and wily, Java has a lot of annoying constraints.

    They did this for a reason though. For a lot of real-world software development, you have to do the work with painfully small amounts of time, money, and talent. So they banned a number of things that it takes an expert to use wisely. E.g., pointers, multiple inheritance, allowing unreachable code, preprocessor macros, raw memory allocation, random memory access, self-modifying code, and so on. As cool as those features are in the hands of a genius, they are plain dangerous in the hands of a mediocre developer. And 99% of the time, the genius will be doing what Java would be doing anyhow; it's only the 1% of the time that it sucks.

    That's why I'd much rather inherit a bunch of J. Random Programmer [tuxedo.org]'s code in Java than almost any other language. There will be little impressive wizardry in it, but there are also unlikely to be many sections that will make me bleed through my eye sockets.

    And you're also right about some of the other feature lacks; the whole primitive type thing is just ugly, and it's clear that they haven't heard about the whole mutable/immutable thing yet. Really, it saddens me that they are just now catching up with a lot of the things that NeXT was doing right with Objective C 5-10 years ago.

    But as far as getting things done in the real world for server side stuff goes, it seems perfectly adequate for all the OO work I do. And to be fair to them, they're making a fair bit of progress [sun.com]; the java.lang.ref [sun.com] package, for example, answered a lot of my gripes about pointers and garbage collection.

    One thing I didn't understand in your post was the section "lack of parametrised types"; could you talk more about that?
  • 3. The performance hit is not minor.

    Although this can be true, for most people it just doesn't matter. Why? A few reasons:
    • Speed is rarely the primary issue - For most projects, things like reliability, speed of development, features, and cost of development are more important than execution speed.
    • Profilers are rarely used - Spending a couple of days profiling and tuning your code will make much, much, much more difference than using C++ over Java. Despite that, there are a lot of developers who never touch profilers.
    • Computers get faster; people don't - Thanks to Moore's Law [tuxedo.org], 18 months from now you code will be twice as fast. It will not be twice as usable, twice as robust, or have twice as many features, and programmers will not be twice as productive. Generally, if I can trade CPU time for programmer time without harming project goals, I'm glad to do it.


    That said, I should mention that I've only done server-side Java stuff. I have no idea how GUI Java programs could still be so damned slow after years of effort, but at least under Linux, they really suck. But this is some sort of GUI library issue, as my console and HTML has all come out surprisingly zippy.
  • 1.Java has NO! parametrised types This means that generic programming is impossible. One specific consequence of that is, that collections cannot be type-safe, and you loose a lot of the help that type-errors can buy you.

    I can very easily override the insertion routeines for collections with, something that calls the instanceof operator... and return if it returns false. This gives me the sort of typesafety you're talking about.

    Java doesn't have "const" (and friends) which means that when you give someone an object reference you have no control over what they do with that. When returning read-only object, the only solution is to clone() them. Very expensive!

    Java does have final, so you can pass parameters can prevent thier alteration.

    But where I really take issue here is the statement that generic programming is impossible in Java. Consider how STL (C++ standard template librarary) defines the use of your own types in its defined datastructures and algorithms library. They say: you must provide your own implementations of (for example) the == operator for list searches to be effective (don't have my book in front of me so can't be more specific right now). This is exactly analagous to saying in java, you must implement a specific interface, and only those classes which implement that interface can be operated on. The fact that you don't have templates is offset by the fact that you do have a common base class (Object), so you don't need templates. I can define a method in java to accept an instance of an interface, I can also define a method in C++ to accept an instance of a base, or virtual base class. These both acomplish the same thing, accept a general type in some algorithm, and allow operation using just a set of base methods. In both cases I can (if I want a big maintenance headache later) try to cast the objects passed in to any type I want to in the method.

    The way you right generic code in Java and in C++ is different, but both allow it.

    --locust

  • by Switchback ( 6988 ) on Saturday December 16, 2000 @02:02PM (#554840)
    This is the type of comment I hear from novice and inexperienced developers. Most new hires right out of college seem to have this fear of debuggers and their debugging skills consist of printf's everywhere. Now don't get me wrong, printf's or some other diagnostic output (such as logging) is very handy to hopefully gain a handle on what is going on, but it's not the solution you want to use if after looking at the output you still have no clue what's happening.

    Debuggers (both command line and GUI) are all essentially the same. Learning one isn't doesn't take very long (on the order of a few minutes) to do the basic things like set breakpoints, step, and watch variables.

    Here are the problems with printf (and other diagnostic output):
    • They don't give you the whole picture and very rarely point you to the exact location of your problem.
    • They have to be maintained. I don't know how many times people have cut & pasted a printf but failed to change its output causing utter confusion. Or the code changes and the printf didn't. They can become a maintenance headache which can actually hinder the troubleshooting process. The should be controlled somehow (preprocessor..some logging level varible etc.) but getting everyone to do that everywhere consistently is also a problem.
    • They can be misleading especially if the output has not been flushed yet.
    • They can get in the way of the actual running of the program and mask bugs (especially race conditions).
    • They can't tell you when a pointer or variable gets stomped on.
    Debuggers on the other hand let you see your entire application state and you can see in an instant if everything is right.
    • If the program crashes you immediately see what went wrong and you can view the call stack to see how it got there.
    • You can easily debug multi-threaded programs because you can force potential race conditions and see if your code works properly or not.
    • You can dynamically alter the flow of your program yourself and force potential problems to check your code behaves properly. Using a debugger is a great way of testing all conditions a piece of code might face: valid input, edge conditions, and invalid input.
    'Debugging' with printf is an iterative and lengthy process of looking at the output, adding more printf's (adding to the maintenance problem), compiling, and looking at the output again. With a debugger, I almost always find the problem on the first or second pass through. You also invariably find other potential problems lurking in the code that just haven't shown up yet. Tracking down a problem with a debugger usually takes me just a few minutes, but going through the printf process takes much longer and may never show you the real problem.

    Think of it this way: You go to a doctor saying you dont' feel well. The printf doctor pokes and prods you until you yell 'ow!'. The debugging doctor uses the intelligent approach where he looks at your symptoms, runs some tests and makes a much more accurate diagnosis of your problem.

    - Rick Alther
  • The problem with going to Java from C++, is that when you dumb down the language, you also dumb down the programmers.

    As we covered elsewhere in this thread, it's true that Java tends to penalize developers (and users) for programmer error a little less than C/C++. That's not intrinsically good or bad; that's just how it is. It's practical goodness/badness depends on circumstance.

    If you're using the language mainly as a training tool, then this insulation is bad. It allows developers to become sloppy, and keeps them from learning why sloppy is bad. A more raw language is a steeper learning curve, but that just means that you get to the high ground more quickly.

    But if you're using the language to deliver a real-world product, then this insulation is good. Your goal is to deliver a useful thing quickly. SEGVs are certainly helpful to the developer, but the user of a piece of crashing software generally doesn't share that opinion.

    And really, the goals of developer improvement and user satisfaction aren't mutually exclusive; you just have to use different tools than crashing code. Instead, you use things like walk-throughs, design review, code review, and pair programming. All of these techniques results in better people, better code, and happier users. And this is true regardless of how forgiving your language of choice is.

    Note also that your argument applies even better to, say, assembler. The closer you are to the hardware, the better your code is likely to be, because there's less to take up your slack. But I take it you don't do most of your work in assembler, right?

    [...]chasing marketing-driven rainbows.

    The silver-bullet syndrome [construx.com] has been around much longer than Java. Indeed, many people had exactly the same gripes about OO programming or, for that matter, C.

    The so called "evils" of C/C++ [...] Are solved quite well with tools [... and] good disciplined techniques.

    Instead of C/C++, you can insert any language in that statement. A skilled developer with the right tools and a sense of discipline can do good work in almost any language. Comparing the work of experts in one language with the work of fools in another is not a very useful thing to do.
  • by HarpMan ( 53271 ) on Saturday December 16, 2000 @02:26PM (#554844)
    Parameterized types are templates in C++. They allow you to do generic programming.

    With templates, you can write a function like this:

    template
    DataType max(DataType a, DataType b)
    { return (a>b ? a : b); }

    This function returns an object by value, and is type safe. By type-safe, I mean that it require s that the two arguments and the return type all be the same (or compatible) types. For example, this would be a compiler error:

    int x = 3;
    complex c(3,4);

    int y = max(x, c); // whoops -- different types!

    This is actually impossible to do Java. You can't make it return a by-value object, and it's awkward to enforce the type constraints.

    Templates allow generic programming, where you write functions and classes (think abstract data types) that are agnostic as to the exact type of some of their parameters. But, you still get compile-time type safety. Templates are great for container classes and algorithms. Container classes in Java are workable, but a bit awkward. You don't have compile-time type safety. The container's values get cast to Object going in, and have to be manually cast back to the desired type when getting an element from a collection. With C++ templates, you can declare containers of specific types, like 'vector' or 'vector'.

    For example:

    vector v(3); // three element vector of ints

    v[0] = 45;
    v[1] = 3;
    v[2] = 4;

    sort(v.begin(), v.end()); // sort the whole vector

    int first = v[0]; // no need to cast

    All of this is type-safe, and about as efficient as hand-written code.

    Also note that the sort function is generic too -- it works for lots of different container types (like list), including container types you write, that the author of sort did not anticipate. Templates are very 'pluggable', both horizontally and vertically. Generic programming has a very different feel from OO programming. It's less hierarchical, easier to plug and play things piecemeal. Of course, you can still use a vector of MyPolyMorphicObject references,('vector to combine OO and generic programming.

    There's a lot more to templates then what I just described. The STL is a great example of a powerful, flexible and efficient generic library. Some people say that ML's generic facilities are even better than C++'s. This may be true; I've never used ML. Other people say that you don't need templates at all, that the real problem is strong typing. In languages like Smalltalk, Python and Perl, you don't have to declare the types of arguments, so every thing is generic. Of course, you can get run-time errors if you pass in the wrong type. But you can also get run-time errors in Java if you try to cast to the wrong type.

    Strong typing without templates is the worst of both worlds, in my opinion. If you're going to have strong typing (which I personally like), then you really must have support for templates or something like them. Otherwise you get the huge proliferation of complicated interface hierarchies that you see in Java, just to make sure that classes are useable various contexts. Templates decrease the need for multiple inheritence (or interfaces) somewhat.

  • Some of my examples didn't get printed properly, leaving of the data type of the instantiations.

    vector v(3);

    should have been:

    vector<int> v(3); // three element vector of ints

    Hopefully that makes things clearer -- the point is you declare the exact type of a container when you instantiate (use) it.

    Should have used preview!

  • This is going to sound heretical, but bear with me.

    If this is at all possible, try developing the initial framework under NT (yes, NT). Let me explain.

    If most of your code is platform-independent, and, in my experience, this is often the case, you will be able to develop on any platform that supports threads if you are willing to put simple wrapper classes around the platform-specific bits. This gives you the double advantage of being able to hide ugly or repetitive API details, as well as letting you port to another platform by reimplementing a simple inner class. I've put together 200-line or less wrappers for threads & mutexes, file IO, ODBC, etc., that work under BSD, Solaris and NT. This makes writing cross-platform code almost trivial.

    Now, about that NT business. NT supports Berkeley sockets, stdio, and almost-POSIX threads, so if you're writing daemons and such, you can write 90% of your code without ever cracking the Win32 SDK documentation. Just use main() and forget all the heinous Windows I/O stuff.

    As to the original question of the post, the development tools on NT are pretty damn robust. If you're willing to use commercial (i.e. pay-for, non-open source) tools, the VC++ compiler and Dev Studio debugger are mature and top-rate. You don't need to use the IDE except for debugging if you don't want - makefiles and the commandline compiler work 98% the same as Unix. The Dev Studio debugger handles multiple threads as smoothly as anything you can find, it has breakpoints and watchpoints, you can view and change memory easily.

    The other commercial tool for Win32 that is invaluable is BoundsChecker from NuMega (now Compuware). The is the most amazing thing for finding both kinds of memory problems - invalid memory reads/wriites and leaks. It runs your app like a debugger would, (optionally) popping up to the exact source line whenever anything tries to write past a buffer (static or alloced). After your app exits, it gives you detailed report of all memory leaks, their sizes, and the lines *and stack traces* where they were allocated. It can run standalone or plug into the Dev Studio environment. This is what I wish Electric Fence could do.

    I realize this is a big change to suggest, and may well be impossible depending on your application/financial requirements. However, if you're in the early enough stages that you're able to change languages/platforms, and you have a budget, then this would be my suggestion: develop the basic app core and threading logic under NT, using Boundschecker religiously. Use makefiles. Periodically move the code to the Unix platform and make required changes to compile. Keep all platform-specific code nicely #ifdeffed. Write simple wrapper classes around any system services that take more than one or two lines of code (again, threads).

    This is how I've been working for the last year or so. I've been writing utilities and daemons that run under NT and Unix, and I'm still amazed at how easily the ports go. It just works. And I will tell you this: The difference between tracing back in core files with gdb and letting your app run in the IDE until the debugger pops up with the exact line of source code, with stack context, where your bad pointer/divide by 0/whatever happened, with the app still running, is indescribable.

    All that said, I really miss Turbo Debugger. Now *that* was a debugger.

  • by q000921 ( 235076 ) on Saturday December 16, 2000 @04:34PM (#554860)
    I've written a number of pretty substantial multithreaded programs, and I have never used a debugger for fixing them. I don't even know what I'd be looking for with a debugger: serious bugs in multithreaded programs tend to be subtle race conditions, and that's not the kind of thing that's easy to track down with a debugger.

    A better way is to avoid bugs in the first place. And for multithreaded programs, a message passing paradigm is generally the best approach in my experience.

    I also use assertions and consistency check liberally, so that problems are caught close to where they occur. As a result, the few serious bugs that I have had were usually solvable by inspection of the source code alone.

    If you are looking for languages that make avoiding bugs easier, look beyond C++. Java is slightly better than C++ for multithreaded programs because errors tend to be more localized, but Java doesn't have much in the way of useful higher-level abstractions for building multithreaded programs. The currently conceptually best languages for multithreaded programs, in my opinion, are SML/NJ, OCAML, and Erlang.

  • I've used both the IDE and printfs for debugging. The IDE is great for tracing flow through deeply nested calls. It's also good for pinpointing problems like infinite loops. For example, you keep hitting F-10, and then it goes grey on line 532. Bingo! That's the function that's gone loopy.

    But then printf is better for checking the contents of things sometimes. For example, after you read in the data file, you can write a simple "dump" function for the data structure to check and make sure that it has the right contents. In general, printf is great when you know what value a variable should have at a particular point.

    As for threads, I can't really say since I haven't done any.

  • ... you must make your code more simple, as you will never catch all possible troubles with a debugger. If multithreading caused it to be more complex, switch to either single thread with nonblocking operations, multiple processes or any combination of two.

    And, of course, Java will ALWAYS remain inadequate by both performance and reliability -- five years is more than enough to fix a bad product even for Sun (ex: Solaris) if it really cared about doing that.

  • Java merely conceals memory leaks by converting them to almost undetectable reference leaks -- different ways, same result, as after few hours or days of running program runs out of memory and crashes (usually crashing a bunch of other stuff in the process). I'll rather have an immediately detectable dangling pointer or traceable leak in C or C++.
  • Yes, it's true that newbies should learn how to use interactive debuggers well, but that doesn't mean that knowledgeable programmers make heavy use of them. The best programmer I've ever met made (or repeated) the observation that once you've dropped into the debugger, you've lost. I didn't fully understand the wisdom of this at the time, but now years later I can see that he's about 99% right on this.

    The wise programmer uses the right tool for the right job, and an interactive debugger is usually the wrong tool. If you have a core dump, it's worthwhile to take a quick look at the stack dump, etc., but beyond that, you should carefully question time spent on further interactive debugging. It's a mental monkey trap--it feels like work and it's the easy thing to do. And five hours later it'll still seem that way.

    The disadvantages listed for printf debugging are either incorrect, or also true for interactive debugging.

    Likewise, the advantages listed for interactive debugging are incorrect, or do not consider the tremendous timesuck that interactive debugging can be. Consider, for example, the first point: Yes, you may immediately discover that a null pointer was dereferenced, but this may well tell you nothing about what really happened. The true bug could have occurred hours ago in a completely different part of the program.

    Stepping through your program is no replacement for really thinking about what's going on.

    This of it this way: You go to a doctor saying you don't feel well. The printf doctor eyeballs you, carefully forms theories about what might be wrong with you and takes various measurements to validate/invalidate those theories. The (interactive) debugging doctor says, "Nurse--scalpel!"

  • by cduffy ( 652 ) <charles+slashdot@dyfis.net> on Saturday December 16, 2000 @07:03PM (#554879)
    The CVS snapshots of gdb have (for the last several months) had vastly higher quality multithreading support than the released versions. Indeed, I think threading only firmed up properly within the first month after gdb 5.0 was released! So grab the repository from :pserver:anoncvs@anoncvs.cygnus.com:/cvs/src, compile it and have fun!
  • ...and multithreaded debugging with gdb (gdb myprogram, not a core dump) works fine.

    Regarding those kernel patches, though: There are several available on linux-kernel. The simplest, by Patrick Wildi, is a patch for 2.2.x which dumps only the thread which actually failed. Another patch by Terje Malmedal against 2.2.x dumps each thread into an individual core file. I'd post links, but (I just realized) my mouse is unplugged so I can't cut+paste; they shouldn't be too hard to find.

    A quick search on Google shows another interesting-looking multithreaded core patch labeled as for 2.4.0t8 by John Jones and Jason Villarreal, apparently funded by Spinway Inc (good 'fer them!). At a quick glance-over, it looks to make a single combined core dump file for all threads. Once again, I can't cut+paste the URL, so you go find it yourself. :)

    There's other work ongoing on 2.4test on the topic; see the thread "Anyone working on multi-threaded core files for 2.4 ?" for more information.

    So fear not, folks, there's light at the end of the tunnel! :)

  • I work on multiple platforms at the Sun-Netscape Alliance. We develop the web server on IBM AIX, HP-UX 11.0, DEC OSF1 4.0/5.0, Linux 2.2, IRIX 6.5, Solaris 2.6/2.8, NT 4.0. The web server is inherently a multithreaded application and a good debugger has been a must in the part of my day job. I find the two best platforms for debugging to be Solaris and WINNT. Sun has with its Workshop by far the best multithreaded debugging tools on any Unix I have seen. Microsoft has a very nice debugger as well for NT as part of VC++.

    IMHO the very worst Unix platform for doing anything thread-related is Linux. And it's got nothing to do with gdb, but with the Linux kernel. On Solaris, Irix and HP, gdb is available and works fine with threads.

    It doesn't work with Linux threads because threads are independent processes in Linux. When you have one applications with 500 threads, it's just not practical to launch 500 copies of gdb on each of the processes in order to set one breakpoint accross all threads. You have to use another platform with decent debugging tools in order to do that.

    FYI, at home I use OS/2, and IBM has an excellent multithreaded debugger too, as part of Visual Age C++ 3.0/3.6 for OS/2. IMHO it's the best debugger of all for threads. Unfortunately IBM hasn't got anything remotely close to it in its VisualAge C++ for AIX.
  • You're missing the point. Java does indeed collect garbage. It doesn't just "run destructors", it doesn't even use a simple "reference count", which still requires a fair bit of baby sitting (eg linked lists).

    Java has proper garbage collection. That is, any object that is no longer accessible gets collected (so isolated cycles of objects get collected for example).

    The issues they are discussing are problems with garbage collection in general, they are not unique to java. You are likely to find yourself facing the same issues if you write nontrivial programs.

  • No pointer errors

    In C++, you can avoid pointer errors if you don't care about performance. Use vector instead of array. Use string. Only use pointers to get polymorphic behaviour. (these pointers are less likely to cause grief than array-style pointers where arithmatic is performed) This use of pointers is not as problematic (for example, in Qt one uses new to create all widgets, but parent widgets always delete their children, so one only needs delete the top level widget.)

    In conclusion, most of the error-prone pointer code is there for performance reasons. And most of the complaints about C++ are pre-STL.

    Exception handling

    Exception handling is part of the standard. Exceptions are first class objects, and can be caught polymorphically. AFAIK, they're not much different to javas.

  • Should we insult your intelligence by explaining why compile-time errors are preferred to run-time errors, or do you understand this ?

  • n lots of circumstances, these efficiency gains Usually more important to efficiency is algorithmic choices and quality of program implementation -- and few developers are worth a damn in this arena.

    So C++/Java is usually moot point regards efficiency trade-offs, because programmers product is such slop anyway.

    I don't know about java, but at least in C++, there are generic container classes, and the C++ standard has performance gaurantees (big-O) on the effectiveness of these algorithms. So it's not accurate that the C++ programmers product is always "slop", because they can reuse well designed and implemented container classes for a lot of their work.

    Java is a lot more productive than C++.

    Or so they say. It's true that C++ code that makes heavy use of pointers is error-prone and needs extra care maintenance-wise, and should be locked up in a library where client code can't see it. But if we only require java-like performance, then why use pointer-arrays instead of vectors, and why use char* instead of string ? Most of the things that are error-prone in C++ boil down to instances of the developer choosing speed over safety. If you want to sacrifice a little speed and forget about pointer arithmatic, you can do that, and you'll still be faster than java.

  • Fare also wrote the vast majority of one of the vastest programming language comparisons I have seem. See The Language Review Subproject [tunes.org] at Tunes.org.

    And Tunes *has* produced at least one line of code...I think it was a prototype implementation of their programming language---Slate, I beleive.

  • Ok, I don't know much about Java so I won't comment on that part of your statement, but I take exception to the comment about Solaris being the best multi-threaded OS out there. (Disclaimer: I work for SGI) The largest system Sun has is the UE10000 and it has at most 64 processors. SGI has built and sold 512 processor systems. Cray has sold 1500 processor systems (though Unicos/mk isn't really multithreaded in the classical sense). So, it seems to me that that title should go to either Irix or Unicos/mk. The Irix kernel is *very* well threaded.

    Lastly, to get back to the topic at hand, the SGI compiler comes with a fairly nice multi-threaded debugger, though I haven't used it very much (I work in the kernel where you basically don't get a debugger other than "printf").

  • The whole point was to have type-safety, and get compile-time errors, instead of runtime error's which may occur after you shipped the product.

    Given that in java I can load a class from anywhere at anytime, the class cast exception may be generated by my code, but might have its root in some code that was made to invoke my code long after I finished it. I don't know if this is completely feasible in Java.

    Java does have final, so you can pass parameters can prevent thier alteration. Java has value constants, not reference constants. Please try to think a bit about the difference: class A { B bInstance; const b getbInstance() { return bInstance; } }

    I never claimed that you could return a constant from a function in general. However, once a final reference is initialized it cann't be changed. So I can go:
    B getB(final C c){...}
    and in the invoking function declare:
    final B b = a.getB(new C())
    They (final B b, and final C c) are reference constants, but I realize this is not what you're after... You want to specify the constness, not to rely on the invoker, then again in C++ what prevents me from casting away the constness? So whats the diff? A properly constructed B will prevent me from altering its internals, and if I lose my reference to it, well its my own damn fault. So if you don't want me to change it, you shouldn't be returning it. You should provide accessors to the relevant data memebers.

    The trick is, that you wish to specify the concrete type that an algorithm work on (specializing the interface if you will, some call this compile-time type refinement), so that you will get compile-time type-errors if the (type-instantiated) algorithm is applied to data of the wrong type.

    I think they might want compile time refinement for the speed... Its faster to figure it out at compile time than runtime. In any case, if I create a class foo. and then declare: list<foo*&gt bar;
    now I try to do a bar.find on this list for some specific foo. Unless I've overridden the == operator for the foo* type this operation will compare pointers not the values of the foo objects. No compile time check will catch this.

    Further after a look around the web, I came across a comparison of OO and GP [camelot.de] and to quote the author: We note that a significant part of the generic programming paradigm can be expressed in terms of C++ language constructs; other parts cannot be expressed by means of the programming language. There are requirements to containers, iterators, and algorithms that are not expressed by means of language features and hence will not even be detected at compile or template instantiation time.

    Under the premise that generic programming requires full knowledge of types at compile time. Java cannot (at least under java 1.2 not sure about 1.3) support generic programming (neither can C++ using virtuals) yet Java Collections looks and behaves a hell of a lot like STL. The latter is by all acounts an example of generic programming. The STL (to me at least) and Java collections represent abstract generic data structures, algorithms, and access methods. The implementation differences are mainly syntactic, as are the compile/runtime differences. These last are a result of the implemtation language not a fundamental property.

    --locust

  • > In particular, does you IDE trigger of a cascade of unnecessary compiles when you make a change, or is it sophisticated enough to figure out which ones are really needed?

    I never use IDEs -- just naked code and a compiler. However, for the two Ada compilers I have used, you get minimal component recompilations based on the timestamp of the source file vs. the timestamp of an information file that was automatically built last time you compiled.

    I'm not sure, but I think this is a requirement in the language spec. Forcing certain dependency recompilations is a safety issue, but forcing global recompilation merely be a waste.

    It certainly motivates modularity, since you can change a line of code in a single module, and then recompile a huge project in half a second.

    --
  • by JohnZed ( 20191 ) on Sunday December 17, 2000 @12:02PM (#554913)
    If you guys are far along in the development process with c++ already, or if you have limited experience with Java and Java threading, you'll just run into worse threading problems there by trying to fit the pthread paradigm into the Java platform.
    That said, I do a lot of multithreaded programming in both Java and C++, and I would give damn near anything to switch completely over to Java. The threading design makes it FAR easier to build correct programs from the ground up without using a debugger. We've known for 15 years that monitors (Java's synchronized blocks, basically) were a better way to write multithreaded programs, and it's embarassing that it took this long to get the idea into a mainstream language.
    Also, you should check out jlint (http://www.ispras.ru/~knizhnik/jlint/ReadMe.htm), which checks java programs for basic errors including many types of thread deadlocks. A lot of commercial Unix vendors have similar tools for C/pthread programs, but I haven't found one for Linux.
    As for actual debuggers, JBuilder 4 is quite good. I've only used the foundation (free) version, but the enterprise edition can also dynamically detect stalls, deadlocks, and race conditions (see http://www.borland.com/jbuilder/jb4/feamatrix/debu gging.html) and do remote, multi-platform debugging. Also, MetaMata (http://www.metamata.com) has a very good debugger that includes some advanced threading features even in their low-end versions.
    On the down side, you'll have to pick a good implementation of the JDK on Linux and stick by it, as the different JVMs tend to have threading incompatabilities. IBM's are quite good, and they support native threads very well. In Sun's 1.2 implementation, at least, native threads were an undocumented feature (with green threads only officially supported).
    Hope this helps!
    --JRZ
  • First of all, this will be my last reply to this (and other) threads (sipposedly) about debugging MT code. We are way off topic here.

    Feel free to take this off line if you like.

    i.e. inserting real's into a list of (conceptually, when you dont have parametrised types) integers.

    I guess, first off I don't see this as so common an error. Next, my point has been that in order to generate the above errors (at least in Java) you must wrap the Java collection in a class whose interface verifies the type. This will give you at least a basic compile time verification.

    On dynamicly loaded code

    Therefore you will not have problems with later loaded dynamic code.

    But then this is a compile time error, regardless of whether or not we have generic programming.

    This is why you need generic programming and parametrised types in the first place

    Parameterised types do guarantee that you don't try to further refine the parameters. But I thought that was just good programming practice, not to further refine the types of arguments, regardless of having or not having templates.

    On constant References, Reader-Writer, etc, and class hierarchies.

    Regardless of the implementation language you can't use finally or const to return your references because both of these rely on the cooperation of the invoker to use finally or not to cast away constness. For the writer, the relevant reference type must provide setValue and getValue operations. For the readers it must only provide get operations. In java this would mean two interfaces. A refValueReader interface and a refValueWriter interface that extend the first. The the monitor writer you put the data to be written in instances of the refValueWriter type, in the readers you are returned instances of the refValueReader interface. In C++ terms the difference is in how you override the functions of the operators on the type. You would have to (forexample) override the = operator to prevent the reftype from being an lvalue in some cases...

    The STL collections are programmed using generic programming, which means, that they operate on any compile-time refined type.

    In C++ it would be hard to implement collections in the OO paradigm, since classes do not inherit from a common base class.

    I'll quote again from the same source: In sum, we achieve genericity by means of a design idea, i.e. separation of data structures from algorithms, and by use of programming techniques supported by the programming language, i.e. C++ class and function templates. Although generic programming uses classical object-oriented C++ language features such as class (template) declarations, it is not object-oriented. How does generic programming contrast to object-oriented ideas? In object-oriented programs abstractions are expressed by means of base classes. In generic programs the abstractions are described in terms of formal, yet verbal requirements. Examples of such requirements are: A container must provide certain iterators. An iterator must provide certain operations, such as increment and dereference. An algorithm must work on iterator ranges.

    In my (admittedly brief) online search for definitions of generic programming that include compile time constraints as a fundamental property of genericity I've come up with: bubkas. The underlying feature is that inheritance is spearated from polymorphism. The problem with it as expressed in C++ is that there is no formal way to guarantee compliance with the stated verbal interface that can be gauraneeted by the programming language. If one looks at the base functionalities of types in C++, and compares them with the base functionalities of (reference) types in Java one notices that they are strikingly similar. Further if one speaks strictly, things such as operators are in fact short hands for function calls of the the nature int plus(int, int). Thus the fact that operator overloading is not allowed in java is irrelevant. The point is that C++ has an implicit common base type (operations I can do any any type, and infact it has a number of types derived from it (pointer types etc) but this is done by the language not the user), where as java has an explict one (Object). Template operations with in STL collections use these implicit common bases in order to be meaningfull. Java Collection operations use an explicit common base to be meaningfull (such is the language). In both cases a greater guarantee can be made of smenatic correctness of a program by insisting on an abstract base class that overrides given default operations. But this would taint the purity of the genericity.

    The key point is that generic programming sperates algorithm from data structure. I can do this in java, but I must stipulate that all reference are to Object. The most generic type. I can also stiplate some semantic ordering of the basic operations on arbirary types, but then the programming language cannot help me short of using object orientation. Java Collections (like STL) allows me precisely this separation of algorithm from datastructure.

    --locust

  • Hi, We develop a fairly large multi-threaded application on various Unix platforms and Solaris Forte (formerly Workshop comes out tops). Multi-threaded debugging is very painful on Linux. strace doesn't work on multithreaded programs (this is the single biggest problem for MT debugging on Linux). I found insight, a tck/tk front end to gdb (available at sourceware.cygnus.com) invaluable during some development on Linux/Alpha. I used a cvs version of it and it is coming along pretty well. IMHO a GUI is a must for debugging, especially for MT apps. (What constitutes a GUI is open to debate, but for me emacs with gdb is good enough). Solaris Workshop debugger on the other hand is excellent to use, though it has it's problems. For example, you can control only one thread at a time. This is true for all multi-threaded debuggers I've come across. I've also encountered occasional crashes. But even with these warts it comes out tops. I've worked on MT applications for over 4 years on many platforms (Solaris, Tru64, Linux, Linux Alpha etc) and found Solaris the best supported among these (despite all the thread related bugs that others have mentioned here). If I can get strace working on Linux and have a stable release of insight on Linux, I'll be happy on Linux too.
  • The gnu visual debugger is based on gdb, and claims to have much-improved support for multithreaded code.

    Similarly, smartgdb [ukans.edu] has long claimed to have improved thread support, although I don't know if it's been kept up to date. The web site doesn't appear to have been updated in a while.

Work is the crab grass in the lawn of life. -- Schulz

Working...