I want my next application to work more like an Internet browser and less like a VisualBasic application!!!
What is it about the InternetBrowser you now use that prevents you from doing just that? Internet Browsers are Clients to the Servers they access. The Server-Side is doing the processing; you are doing the Accessing. Just get the fastest possible connection and the fastest possible Computer and you shouldn't see Hourglasses or lock up (at least from your machine).
Why should an application ever "lock up" the UserInterface and display the hourglass mouse icon, when it has some valid data it can display to the user? And why should applications refuse to interact with the user until all possible data that the user might need has been downloaded from the relational database, across the network?
With a browser, the basic format and background text always appear quickly, even if it takes a while to load all the graphics. If the user sees fields they want to fill in, or links they wish to traverse, they don't have to wait for the graphics to load - they can just interact with what's there and go on.
I wish we could do this with conventional business applications that access relational databases. Why does the system have to lock the screen until all records are downloaded and displayed in the grid? The data the user really wanted might have been in the header, so why do we lock up the application and force them to wait? The data the user really wanted might have been in the first few lines, so why do we lock up the application and force them to wait?
I generally consider long lists or data-grids to be a design smell. Given A choice, I have a QueryByExample type of screen which limits what is being sought for. I put in a limit of say 200 to 500 result records with a message at the bottom indicating quota has been exceeded. This reduces the problem of long down-load waits. Besides, scroll-bars can cause odd or confusing behavior if the results are in the process of changing while being scrolled. -- top
I may have missed the plot, but DoingMultiThreadedGuiInVisualBasic isn't that hard.
Now it's true that if you had lots of time and money, really creative developers could do everything, including relational queries, with event callbacks, asynchronous calls, and signals. But you pretty much have to throw away all your existing productivity tools to do it.
So that's why I think that "multi-threading" GraphicalUserInterface work would help, if tools supported paradigms that made it easy. When displaying a screen for invoices, for instance, the screen could kick off a "thread" to fetch the invoice header information, and another thread to fetch all the detail lines and populate some kind of grid. Which shouldn't take more than a few milliseconds, a blink of the eye. Each thread could be written simply; it would issue blocking SQL calls, then populate and enable fields when it gets the data. Aborting (leaving) the screen would abort (kill/throw exception in/send a message politely asking it to stop) any threads that hadn't finished their work.
As I see it, all "background worker threads" would quickly block on database or network calls, so there would be no need for interrupt-driven pre-emptive multitasking. The "threads" would have to be careful about conflicts when accessing shared data: the screen controls. But the proper processing of screen events while other events are processing is already an issue with some tools, so it's may not be a big problem. And a simple solution is available for the most common cases: Disable a control (or grid line) until it's ready for user input.
-- JeffGrigg
Non-preemptive threads (also known as "fibers" in the Win32 API), along with good GUI library support, would fit the bill nicely.
[Non-preemptive threads/"fibers" mentioned by PierrePhaneuf on the ThreadsConsideredHarmful page.]
Something truly blocking that wasn't hooked up by the Win32 fibers API (say, an SQL query) will block the whole application I think. Fibers are non-preemptive, and will only give control to other fibers when "given a chance" (doing blocking I/O that it intercepts, using the "yield" function).
Maybe it's because I come from a Unix background, where nearly everything can be made non-blocking and select()ed in some way, but I see voluntarily synchronous APIs as quite distasteful. For example, in an SQL query, there is a file descriptor somewhere that we're waiting for its readability (the socket to the database server for example). Why does the SQL library keep that file descriptor for itself and act rudely, when it could just make that available? -- PierrePhaneuf
The simplest case mentioned above, where you've got a basic GUI CrudScreen and you want to provide async database calls is actually pretty simple. The first point to remember is that in any GUI application, you're working with resources which aren't yours and may very well not be thread safe. In fact, I don't believe that any GUI engine in common use is fully thread safe, because of the significant performance limits that much synchronization entails. In my experience, the best solution is a simple async api using message passing - you start a query, the query posts a message back to the main thread when it's completed. I've used this technique many times to implement an async api on top of a synchronous one.
May I ask why it would be "great"? I would like to study some UseCases of it being helpful. I would rather the GUI tool make it easy to spin off another instance (like launching an EXE) the few times it is needed and make it easy to coordinate the instances. -- top
I'm very confused by this page. All CRUD business apps I write load the data asynchronously and don't lock up the GUI. Every single GUI framework allows you to do this. It really is very easy to do. After all, what do you think a web browser is but a GUI application?
This CrudScreen thing reminds me of a MultiThreadedGui? I wrote for my AssemblyLanguage homework long time ago. We had to do a memory HexEditor? (in DOS). I separated the display fully from the editing: The display would fully refresh in the timer irq (it reread the memory portion under consideration, so changing memory locations were permanently up to date or would even flicker if changing quickly).
The input keys were translated into actions as usual (e.g. cursor movement simply changed some position variables and the display irq would do the rest). It had no noticeable delay whatsoever; e.g., loading a file from floppy might take some time, but you could happily scroll and see the bytes load.
This is also the approach taken in ColorForth's UI. See HexDumpInManyProgrammingLanguages. -- IanOsgood
One issue is how to deal with long-running reports that run on the server. One approach is to have the client wait on the process, but perhaps a better approach is to let the user view the status or report queue, perhaps with a "refresh" button. This way the client is not tied up such that one does not have to worry about multi-threading. Multi-threading can be tricky for both the programmer and user, so if one can farm long-running reports off to a report processor, it simplifies the client-side. Plus, if one shuts down their computer, the report server is still processing or still has the report results there (for a set duration). However, there are not a lot of frameworks for report-server monitoring such that you may have to roll your own.
[This discussion extracted from ThreadsConsideredHarmful.]
See PrematureConcurrency ThreadsConsideredHarmful EventQueue EventDrivenProgramming WaitFreeSynchronization LockFreeSynchronization SynchronizationStrategies GuiThread