Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which implications does multithreading have on the architecture of a desktop application?

I am writing a multithreaded desktop application.

Generally

I am unsure about the implications that multitreading has on the architecture. There is a lot of literature on architecture, but I know none that takes multithreading into account. There is a lot of literature on the low level stuff of multithreading (mutexes, semaphores, etc.) but I know none that describes how these concepts are embedded into an architecture.

Which literature do you recommend to fill this gap?

Particularly

My application consist of

  • Presentation that creates and manages dialogs using a GUI toolkit,
  • Kernel that knows all about the domain of the application,
  • Controller that knows the Kernel and the Presentation and moderates between these two.

To be more precise, here is how files are opened:

  1. The Presentation signals a FileOpenCommand.
  2. The ApplicationController recieves this signal and
    1. uses the ApplicationKernel to create a File object,
    2. uses the ApplicationPresentation to create a FilePresentation object,
    3. creates a FileController object, passing the File and the FilePresentation to the constructor.
  3. The FileController registers itself as an observer on its File and FilePresentation.

Let's say File provides a long running operation Init() that should not block the user interface. There are two approaches that came to my mind:

  1. File::Init() returns an object that encapsulates a thread and can be used to register an observer that is notified about progress, errors, completion etc. This puts a lot of responsibility into the FileController (who would be the observer), because it is now accessed from both the main thread as well as from the working thread.
  2. Hide the working thread completely from the Controller. File::Init() would return nothing, but the ApplicationKernel would signal creation, progress and errors of long running operations in the main thread. This would drag a lot of communication though the ApplicationKernel, turning it into something like a god object.

Which of these two is the common approach to multithreading in a desktop application (if any)? Which alternative approaches do you recommend?

like image 690
Oswald Avatar asked Dec 28 '10 16:12

Oswald


1 Answers

I suggest that you consider using the actor model. It is a concurrency abstraction that hides a lot of the details associated with threads, locks, etc.

Edit

Some additional comments spurred by @CMR's comment...

Under an actor model, I imagine that the application would still be structured using the same components as suggested in the question: Presentation, ApplicationController, etc. The difference with the actor model is that the components (now actors) would not hold direct references to each other. Rather, they would hold channels to which they could post asynchronous, immutable, messages to one another.

The sequence of events in the "open a file" case would be essentially the same in the actor model, except that channels would be passed to the FileController in step 2.3 instead of direct object references. Similarly, observer registration in occurs through channels.

So what's the difference? The main difference is that none of the code needs to be thread-aware. Threads are invisible to the application logic, being the concern of the actor framework. If one can follow the discipline of only passing immutable objects through the channels (which some actor frameworks enforce), then virtually all the difficult logic associated with thread synchronization disappears. Of course, one has to switch mindsets from a synchronous programming model to an asynchronous one -- not necessarily a trivial task. However, it is my opinion that the cost of that switch is outweighed by the benefit of not having to think about thread-safety (at least in systems of some complexity).

In UI programming in particular, asynchronous models make it much easier to give nice user feedback. For example, a UI element may kick off a long-running task, display a "working..." message, and then go to sleep. Some time later, a message arrives delivering the results of the long running task which the UI element then displays in place of the "working..." message. In similar fashion, tree views can be built incrementally as each tree node's data arrives in an incoming message.

You can think of an actor model as a generalization of the classic UI "event pump" approach -- except that every component (actor) is running its own event pump simultaneously instead of one pump dispatching to a bunch of components. Actor frameworks provide a way to run large or even huge numbers of such "simultaneous pumps" with very low overhead. In particular, a small number of threads (say, one per cpu) service a large number of actors.

like image 151
WReach Avatar answered Sep 29 '22 18:09

WReach