We need a GUI thread.
…is a common developer’s reaction when the application only responds slowly to user clicks. The developer might be right: when some (gui) events require a lot of processing then having more than one thread, e.g. a GUI thread and one or more worker threads, is one of the solutions. The GUI stays responsive because processing is done by the workers. An example of such a GUI could be an IDE or a graphics rendering tool.
In the embedded world though, a lot of GUI applications are no more than:
- read message from device -> parse message -> update gui, and
- get gui event -> create message -> write message to device.
Processing is minimal. Threads are not really needed because every event is processed within a few tens of milliseconds. If the application is well written, the user won’t notice any UI delay, even with only one thread. Of course, there still might be a scalability issue (e.g. how to handle 2000 events per sec?) but this does not restrict itself to single threaded designs. We will come to this later.
The single-thread approach is not limited to GUIs but, more generally, is applicable to event-based I/O applications (in contrast to cpu-intensive applications). An event could be anything: a gpio that toggles, a socket which becomes readable, a gui mouse click, a timer that goes off etc.
Consider for example a basic embedded application which:
- needs to communicate on the CAN bus, and
- has to control some GPIOs and read some ADC values.
If cpu-power is not required then in order to be responsive, communication should never (significantly) delay I/O control, or vice versa.
How to write such a program? How to make sure that when some bytes have to be written to CAN, the socket is not going to block? This will be discussed in Part 2 in which we’ll explain how to write a non-blocking, event-driven application in a traditional Linux way without using O_NONBLOCK.
Addendum: What’s wrong with threads anyway?
Nothing really, but for these low-processing, event-based I/O applications, threads may only introduce unnecessary complexity (concurrency, synchronization, locking, starting/stopping threads etc.).
On the contrary, a single threaded design has simple, sequential logic and is therefore, typically, a better choice. Additionally, an application with several threads is not necessarily faster (e.g. because of the overhead of context switches and system calls for locking).