“The primary intention of my previous article was to make it very clear why and when locking is needed in multithreaded applications. In this article, I want to present my experiences in writing a new prototype for a replacement of the document model in WonderBrush and how it is manipulated and rendered asynchronously.”
That’s pretty much what RCU (http://en.wikipedia.org/wiki/Read-copy-update)does in the linux kernel. It’s a good thing that desktops are using the idea.
Sounds like what this is doing is more complicated than it needs to be. Single-threaded drawing apps have been working for ages without significant lag. All this snapshotting likely increases the memory overhead for minimal speed benefit versus WonderBrush-esque apps on other OSes.
Edited 2007-09-10 02:47
Sounds like what this is doing is more complicated than it needs to be.
Welcome to the brave new world of multi-core, multi-threaded applications… Please let us know when you’re ready to join us
Single-threaded apps are a monstrosity on the Desktop. The downside of single-threaded applications (or even single-threaded updating of the GUI) can clearly be seen in Windows, where such behaviour is very common.
Single-threaded behaviour results in this: On Windows XP, you can’t even move a window on screen if it’s single threaded application blocks on something. (Quoting from the article). Of course there is a work-around here (very good on multicore systems). You can under “Folder options” turn on the option to open folder windows in separate processes. And you can in the registry turn on an option to run the Desktop in a separate process.
A typical application window in Windows goes white under heavy load or under a longer process (liking unpacking an archive) because unpacking happens in the same thread as the GUI-updating.
Summasummarum: Either you use extra processes or you use multiple threads. Never ever code single-threaded. Bad habit. Bad bad habit.
While I agree with the statement about single threaded application completely, I fail to see the problem with the one GUI thread – many worker thread approach. And you did not explain that in your comment either.
I find it, once learned, easier to use, since you separate the presentation logic from the business logic clearly. If you have x threads in your application, each of which may or may not access the GUI, that can make the code much more difficult to understand.
As a sidenote, I have always found Windows applications quicker than Linux ones, at least on the GUI. And Linux applications are not free of the single threaded problem, either. Especially package managers: I have yet to see one that can update its screen properly while querying the package list. I have not used BeOS, but I will try Haiku as soon as it is ready; it would be nice to have an OS that is really desktop-oriented.
>Single-threaded drawing apps have been working for ages without significant lag.
Well apparently you are very tolerant, not everybody is like you: I just switched from FF to Opera because I couldn’t bear anymore FF’s UI non-responsiveness..
UI responsiveness does matter.
I have not tried Photoshop in a while, but last time I did, I was not so happy with the shape editing for example. The document updated no sooner than when I released the mouse! While manipulating the path, only a preview was shown. When I tried Xara, the graphics would switch from realtime update to preview as soon as things got too slow. I didn’t find that ideal either. I have worked with many apps over the years… whenever manipulating something is locked to the rendering speed, things become painful. What’s also important is that on multi-core computers, threads are actually running in parallel, and without threads, your app uses much less resources than would be available. I don’t see the argument against multi-threading. It’s a little more complicated? So what if the result is better.
…is like pulling teeth. Many BeOS applications were full of multithreading bugs. They always kind of worked, but were never really stable.
Modern languages like scala make writing multithreaded apps much easier. Scala has a very powerful message passing library (actors) that is somewhat similar to the erlang approach. The pattern matching of scala makes writing message handlers extremely pleasant.
http://lamp.epfl.ch/~phaller/doc/ActorsTutorial.html
“Writing multithreaded applications in C++ is like pulling teeth”
That’s a bit of a weird statement. Doesn’t that totally depend on the available API?
It does depend on the available API to a certain degree. Writing multithreaded applications using the BeOS api is certainly less painful then writing them using the Win32 API.
And using a transactional memory library writing low level/high performance multithreaded code can be almost bearable.
But for example implementing message passing is much more pleasant in a language that has support for pattern matching. And generally writing multithreaded code requires good support for immutable data structures.
A garbage collector is also immensely helpful for message passing. C++ has neither of those, so it is just a bad choice for multithreaded applications.
I don’t understand what you are trying to say at all. It sounds like you are saying C++ sucks just because it doesn’t have everything you need built into the language. Where did you get the opinion that most BeOS apps are laden with multithreading problems and very unstable. What would those problems be?
I am wondering what examples he has too. Every program that seems to have problems under BeOS appear to be ports of single threaded programs.
Since the code was never multi-threaded in the first place, hacking it to work under BeOS tends to expose design decisions of the original code.
I have not seen any such problems with programs written proper for BeOS except for ‘DriveSetup’ which always act weird to me.
I was a big fan of BeOS way back. I even wrote some programs for it: http://www.gamemakers.de/tools4b/ . But while BeOS itself was pretty solid for me, I often had stability problems with third party apps.
IMHO the only way to make multithreaded programming acceptable for mere mortals is to have higher level synchronization primitives. Message passing is obviously one way to achieve this. The BeOS people knew that, so they made many of their APIs use message passing.
But writing a message handler in C++ is just a pain. First of all, you need to have strict rules for the ownership of the objects contained in the message. Otherwise you have a memory leak or a double free bug. Then you need to manually decompose the messages. The list goes on and on.
So just because you had problems with third party apps crashing it’s bound to be because of multithreading?
Ownership and garbage-handling, even with a garbage collector, is something you should always know and handle. For instance if you keep just one ref to an object it will most likely never be garbage-collected.
I don’t agree. The problem is that a lot of developers just won’t or will not understand multi-threading. Using a language that “hides” the locking & message passing details may help mitigate that problem somewhat, but they’ll still have very little idea of how it works.
Writing multi-threaded C++ is easy. There are three or four rules to remember and that’s about it. Any developer should be capable of it.
Exactly.
The majority of developers are incapable of writing multithreaded code with fine-grained locking. That is just a fact. So your approach is to tell these people to learn low level multithreading primitives or go to hell. Great way to get new developers for your niche platform.
First of all, scala does not hide the message passing details. It just lets you write a message handler in 1/10th the lines of code compared to C++.
And what is the problem about hiding complexity? Many people use the stl without having the slightest idea about the alorithms used by it. Are you saying that abstraction is bad?
Besides, just because somebody does not get low level threading primitives like semaphores and mutexes does not mean that he is a bad programmer. Maybe he has valuable domain specific knowledge.
And I guess all those people using Erlang to program high performance telecommunications gear must be idiots because they use a language that hides many multithreading problems…
‘The majority of developers are incapable of writing multithreaded code with fine-grained locking. That is just a fact.’
So most programmers won’t understand this article at all then?
Yes. And of the maybe 20% of developers that understand the issues at hand, only a very small part will be capable of applying this correctly every single time. Besides, don’t you think that the solution presented in the article is a lot of code for something so conceptually simple?
You are omitting something which I mentioned in my article several times, which is that the code got _cleaner_ instead of more messy. From just the code that I posted, you wouldn’t see this, but the important bit is that the rendering related code got separated out of the document model code. The ObjectSnapshot derived classes contain all sorts of code related only to rendering, while the Object derived classes are freed of it. In another words, the majority of the code that is in the snapshot would have to be _somewhere_ anyways. The code for adding the proper locking on top is very little. And it doesn’t have to grow with more objects/features. The only duplication of code is in storing the object data in the object and the snapshot, but even that could be refactored. Then you would be left with very little overhead code-wise.
Today I have a vague knowledge about multithreading and I think that to become a better c# programmer c++ have helped me a lot. When I have time I will read this article and probably understand it perhaps not everything but the I can ask (#Haiku) if I think it’s interesting what better is this are on an OS I love and are using my C++ experience on. (Some day I would like to make a driver as well) and those that don’t like C++ and multithreading don’t read it.
I don’t think anyone writes for those that don’t want to read there article/books but for those that want
I don’t see the point. “20%” is just a number you picked. If you were more arrogant, you might have picked “10%”, if you were less, maybe “30%”… 🙂
Yeah, maybe not all programmers might be capable of applying this correctly every time. On the other hand, my article might be helpful to some. Some might even find yet a better concept. Maybe one of those will write another article and I will learn something.
I just don’t see your point.
You are just saying that programmers write buggy code and adding a feature adds to codesize.
Features can actually reduce codesize though.
I still don’t believe it. You’re basically calling the majority of developers idiots.
This claim is based on API-specific details. I can write a message handler in C++ for Syllable (& BeOS would be similiar) in under 10 lines of code, and that’s with a very generous white-space policy. I could collapse that to 5 lines with BSD-style indentation.
I never said it did, but I’d be concerned by any developer who did not have a basic understanding of what is happening below the surface of the code they are developing.
Apart from the fact that is an ad-hominem, it really depends on wether they are using Erlang because they don’t understand threading or because Erlang is highly suitable for the given domain-specific problem. As it is the later, your assertion is false.
Edited 2007-09-10 13:59
I work with many scientists and engineers. None of them are idiots. In fact, many of them are quite smart and also good programmers. But most of them do not get low level threading primitives.
Maybe a message handler for one specific message type. If I remember correctly, a BLooper processes BMessage objects which are basically hashtables. So to handle multiple different message type, you end up with a giant switch statement. In each branch of the switch statement, you have to manually extract all message parameters from the BMessage. For a complex message that will be several lines of code for each message type just for the decomposition. And then you need to handle the case where some parameters are not present or of the wrong type, etc.
In a language with pattern matching, all that is just one line of code.
There is a huge difference between understanding how e.g. a mutex works in principle and applying them correctly every single time.
Most of them probably use erlang because they understand threading so well that they know that low level threading primitives are very error-prone and result in very hard to find bugs.
You clearly have a pet language, so this discussion is kind of pointless, but there is one thing I want to pick up:
The thing is, all of this is trivial and no more difficult or error prone than any other form of procedural programming. It’s a total non-issue, and irrelevant to any argument about threading issues, other than the fact that message passing is a good solution to reduce locking. How it is implemented is irrelevant. It’s well known that C & C++ are verbose when compared to newer HLL’s. If Kaj wern’t so busy I’d ask him to come tell you about how wonderful and compact REBOL is.
So you are saying that writing 10 LOC is no more error prone than writing 1 LOC?
Don’t get me wrong here: I used to love BeOS, and I even think that using C++ to write the core OS parts of Haiku is a good idea. I also do not want to criticize the author of that article. But I sincerely think that C++ is a very bad choice as a language to write multithreaded applications.
But I sincerely think that C++ is a very bad choice as a language to write multithreaded applications.
Or whatever non HLL. We got it. Thanks.
Now, whatever the language, designing applications that scale well both on responsivness and computing raw power needs developers used to threading design patterns.
No language will know better than you what and where in your application it matter more to use parallelism and where it make no sense at all and, worst case, could even be counterproductive.
Parallelism doesn’t oppose procedural language but sequential programming. Two different things. Some language can have built-in parallelism support, sure. And? Doesn’t make any threading design pattern article automatically useless.
Edited 2007-09-10 21:02
Most unstable applications for BeOS were/are those ported from other platforms (usually with focus on single-threaded behaviour). Native BeOS applications have a reputation for being quite stable.
…it boils down to where any individual sees the pros and cons and how important they are to her/him. I am setting my hopes on Haiku, because no other OS currently satisfies me. This might sound crazy for most other people, but the point is that some do think like me. And there is a subset of those people who are developers and want to write great multi-threaded apps for Haiku. With those people, I want to share some experience, that’s the whole point of my articles. It doesn’t matter much to us that there is a programming language on a another platform, which might have some features that C++ does not have (built-in). The likelyhood is great that that language it has some cons as well. The API that is available on Haiku/BeOS (and Syllable) makes message passing and multithreading easy enough. Yes, there are issues that developers interested in writing apps for these platforms have to learn about, but that is were articles such as mine might help.
Todays x86 processors, from INTEL & AMD, are Multi-Core -> fact
An OS, like BeOS/HAIKU/Syllable(/MorphOS?), that is multi-threaded in design will “effectively” use all processor cores ( to there fullest; provide the “best” SMP ) & provide a more responsive / faster system. -> fact
Now, not all applications have to be multi-threaded on an OS like Windows or Linux. Those that barely use the processor could be single threaded in design but you lose out on system responsiveness ( & efficient multi-core usage ). On Windows, Linux, OSX, etc. – any & all programs that heavily make use of the processor should be multi-threaded though because of multi-core benefits.
These days, the more popular programming language seems to be C/C++ . I can’t personally say how good it is for creating multi-threaded programs, though most native BeOS programs work very good for me without problems, but because most developers use ( or know of ) C/C++ – then these are the best programming language(s) to show how to write multi-threading on. And how well multi-threading is implemented in a program will depend on the the developer’s knowledge, skill & experience – some developers will be better than others at writing or understanding it.
With Multi-Core here, developers will have to start learning how to program with multi-threading because at some time or another they may need to do it on programs intended for Windows, Linux, OSX, etc.
Edited 2007-09-10 17:09
…and for folks on OS X the preferred language is Objective-C which can leverage both C and C++–through ObjC++.