6 ms·
Well, its also a poorly motivated dream unless you have a sexual fetish for the Java style of abstraction where everything is completely independent. Who the he
by frozenport 11y ago
Well, its also a poorly motivated dream unless you have a sexual fetish for the Java style of abstraction where everything is completely independent. Who the heck wants multi-threaded GUIs?
User interaction proceeds sequentially, so most objects don't require locks. The rare exceptions in my software is rendering or IO on a separate thread, and these don't nicely fit abstraction models, as mentioned in other posts they involve C-style state machines like OGL.
A multi-threaded GUI seems like a great way to kill performance, with little advantage.
- AndrewDucker 11y agoYou want a multi-threaded GUI when it's running a long task. Otherwise it won't update until it's finished running, there's no way to cancel the task, etc.
- panic 11y agoYou don't need a multi-threaded GUI for that. You can have the GUI running on one thread while the task runs on another.
- lmm 11y agoSure. You put a message queue in there and create command objects for all the updates that tasks might want to make to the UI. It's not hard; in fact it's thoroughly mechanical, so it's exceedingly tedious to program. So why isn't the computer doing it for me? I'd happily sacrifice some performance if I could just write the change I wanted to make in the thread where I wanted to make it, and have the computer take care of the bookkeeping.
- devit 11y agoYou can just send a closure to the UI thread and have it executed there, provided you are using a good enough programming language. Or start the long-running computation from the UI code in a way that returns a promise, and chain the UI update on it, in a way that causes that continuation to be scheduled on the UI thread. Or have an UI that can be updated from any thread (but not simultaneously) and take the big UI lock.
- vesinisa 11y ago> it's exceedingly tedious to program. C++ programmer detected? ;)
- lallysingh 11y agoJust have the ability to send closures (std::function) to other threads' message queues. Then you can use inline lambda syntax.
- frozenport 11y agoIn modern frameworks like Qt the message loop is mostly hidden. An astute observer will also note that at the bottom of every Win32 program is a message loop monitoring events such as for when the window is closed.
- Arnt 11y agoUh-huh. Typically GUI work is instantiated with the GUI toolkit on the call stack. It calls foo.onClick(), etc. Now, if one particular onClick starts long-running task, then there are three possible designs: Either that particular onClick() starts a worker thread and returns before the worker is done. Or the GUI toolkit delivers the onClick() in a thread of its own, e.g. from a pool of workers. Or everything is done in one thread, and the UI blocks. The last one seems sucky, but the insidiously sucky one is the one in the middle. That's where every user's implementation of onFocusOut() must take care to lock because all of bar.onFocusOut(), foo.onFocusIn(), foo.onMouseUp() and foo.onClick() are called concurrently in four different worker threads. The tail wags the dog.
- sagichmal 11y ago> Who the heck wants multi-threaded GUIs? Widgets aren't static; presumably you want them to keep updating (spinners, size changes, status updates) when the user is interacting with other elements.
- panic 11y agoModern single-threaded UI frameworks don't go into a loop while you're interacting with something. Say you click on a button and drag. This enters the UI framework as a "mouse down" event followed by several "mouse dragged" events. After handling each event (or between events), the framework can decide to do other work, like updating a spinner.
- jameshart 11y agoThat's not a "modern" GUI framework approach - eventloops have been a feature of GUI systems back to the Apple Lisa and Windows 1.
- panic 11y agoYes, event loops are quite an old idea. I just put "modern" there to exclude old systems that encouraged polling. For example, I'm pretty sure classic Mac OS entered a loop while tracking the mouse in menus.
- deleted 11y ago[deleted]
- vidarh 11y agoAnyone who has seen the responsiveness of e.g. AmigaOS under heavy load next to many modern systems might be inclined to want (more) multi-threaded GUIs. Heavy use of multi-threading to disconnect GUI updates from the actual work was essential to making that happen. AmigaOS sacrificed throughput over responsiveness all over the place (e.g. something as trivial as cut and paste from a terminal would easily involve half a dozen threads with message passing). You don't need separate threads for every little component, though.
- fulafel 11y agoWas the UI really heavily multithreaded compared to today's systems? I thought there was a lot of events and message-passing going on in AmigaDOS much like in current GUI systems.
- vidarh 11y agoDepends on what you mean by "heavily multithreaded". And yes, you're right, there were lots of events and message passing, but that message passing went between different threads. I mean to write this up for a blog post and do some proper diagrams, but here's a rough overview of the state transitions when handling terminal IO for AmigaOS and reimplementations of the API, like AROS (this is where I got hands on experience with it - I extended the AROS terminal handling): Low level interrupt sources will be handled by "devices" such as "keyboard.device" and "gameport.device" (the latter handles the mouse/joystick ports). These will feed input events into "input.device". The input.device is opened by any component that wants to handle input events. This includes the "console.device" which is responsible for providing a "raw" terminal in a specified rectangle in a window. It handles low level input processing, and turns keyboard and mouse input that are relevant to the console/terminal into higher level events which it passes on to clients, as well as take commands (such as "move cursor to position (x,y)" or "write text xyz" and render the terminal). Above the console.device sits the console-handler (applications can, and often do open console.device directly if they want a low level interface). This is responsible for opening a window, creating a console.device that covers the window, and "cooking" low level input into higher level input and vice versa for output. The "gadgets" (widgets; buttons etc. in the windows) will be handled directly by intuition (the GUI system) in a separate high priority thread. If you then do cut-and-paste, there are additional complications: "conclip" needs to be running. This receives requests to cut or paste via messages, and mediates access to the clipboard.device. The clipboard.device again manages reading/writing files in the relevant clipboard volume. That will involve talking to the appropriate filesystem handler, which again may write to a device (such as trackdisk.device for the floppy drives). Pretty much all of these components will run as their own separate threads. And most of their interaction is via messages put on a queue. So if you choose to "cut" a section by pressing a key combination, an interrupt will be fired to keyboard.device, which will add an event via the input.device which the input handler thread ("task" in AmigaOS) will pass to the console.device thread via a message, which will pass it on to the console-handler, which will pass a message to conclip, which will pass the data on to the clipboard.device which will send a message to the relevant filesystem, which may send a message to a low level device. After sending a message to conclip, the console-handler will send a message back to the console.device if there's any rendering required. The reason for all of this is that coupled with careful priorities (UI rendering and input is running in high priority threads), the system appears very responsive, while a lot of this happens behind the scenes. E.g. the clipboard system on the Amiga has to deal with a system where the clipboard could have been reassigned from the ramdisk where it'd usually be, to floppy, so it really couldn't reasonably be "inline" without making the system unresponsive. In that respect AmigaOS was more multithreaded: There's all kinds of things we consider fast enough to do "inline" now that was put behind a thread-boundary because it was either unpredictable or too slow to be done inline back then.
- Retric 11y agoMultithreading the GUI adds a lot of responsiveness. Sure, even your phones CPU has 2+ cores at 1+ Ghz, but if it still shudders then your OS programing model is wrong. PS: I have yet to see a single threaded GUI I can't make shudder while playing video.