You might be surprised to read that Ecore provides IPC and networking abstractions but not any kind of thread API. Thread support seems to be important these days and most support libraries (as Ecore in the case of EFL) usually offer some sort of wrapper around UNIX threads. The fact is that Ecore takes a completely different approach when it comes to "parallelism". Rather than employing threads, Ecore focuses instead on a powerful event loop mechanism. If you know everything about thread versus event based programming feel free to skip ahead.
Console programs are straightforward to program when it comes to parallelism. The application is in control, while the user just waits the execution to finish. Interaction happens either before the application starts (command line arguments) or only at rare cases during runtime. In the latter case the application stops working and asks the user for required input. With GUI applications the situation is reversed. The user is now in control and the application must respond to user actions (which come in the form of events). Since a GUI application must continue working and updating its window even when the user has assigned some work to it, a form of parallelism is needed. The GUI application must do at least two things at once (GUI in the foreground, processing in the background).
Threads come in the rescue for this kind of problem. One thread is managing the GUI and one or more are processing in the background. The concept is well known but also well known is the fact that thread programming is difficult. When threads have to share common resources the programmer must be extra careful to avoid racing conditions and use locking to avoid corruption of data. Without getting into details, we should just say that a badly written threaded application has bad performance in the best case (because of locks) and serious problems in the worst (deadlocks which result in application freezing). Threads need also special libraries for implementation and special debugging support from the run-time system.
An alternative approach for this is event driven programming. Here all pending actions (jobs to do) are queued in a single "list". The running application looks at this queue, selects one
job to serve, then comes back, selects another one and so on. There is only one control flow at a time which simplifies programming (no locks/racing conditions). If you have
ever used the poll()
or select()
UNIX system calls which act on file descriptors you are already familiar with event handling.
Of course even driven programming has its drawbacks too. The performance is not always optimal if the queue is too large (compared with using threads). Threads also
have gained great momentum with the coming of multiprocessors (where a thread can be served by another CPU in a truly parallel way).
The following table compares the two different approaches.
Table 5.2. Threads vs Event based programming
Threads | Events | |
---|---|---|
Programming effort | High | Low |
Locks needed | Yes | No |
Possible Deadlocks | Yes | No |
Debugging | Hard/Impossible | Easy/Trivial |
Good for | Many independent workloads | A few intermixed workloads |
Bad for | Too many shared resources | Too many workloads |
Ideal in | Multi processor/core systems | Single processor/core systems |
Ecore chooses the Event-driven approach. Notice than in the case of uniprocessor systems, since only one control flow is active at a time, you never have true parallelism no matter the approach you choose. It is just a matter of convenience.
The Ecore event loop already deals away with a lot of events. You do not need to write event handlers for several window actions such as moving/resizing/exposing. You do not even need to decide when to repaint your main window (previously shown in the Evas chapter). In general if your application is simple enough you do not need to deal with events at all. Just draw your items in Evas/Edje and everything is done automatically for you behind the scenes. When the interface changes (values updated, UI elements added/removed) the application will manage everything by itself.
So why do we devote a separate section on the Event loop in Ecore? For the simple reason that you have some capabilities not easily found in other toolkits. The first is that you can add manually jobs in the event loop of the application. These will be served by Ecore in a best effort manner. This means that they will be served eventually by the application but you cannot predict when exactly.
The second capability (which is more interesting) is that you are able to decide what your program does when idle. That is, you can specify a callback function for situations where your application waits for I/O or user input. The callback function will be run using whatever CPU percentage is available to the application. Taking this idea a bit further, Ecore additionally allows to define what happens when the application enters and exits the idle state. In result, you can program a really complex EFL application without using any threads at all and delegate all processing into "idler" functions. This gives EFL programmer great flexibility.
If you still believe that threads are essential, you might not know that your X-Server is a single user-level process (no ties with the kernel OS) which handles all on screen drawing via Events. If a whole implementation of the X architecture is possible with events then certainly your application can refrain from using threads too.
Closing this section, we need to note that if you need to run a function at a specific interval during run-time you are always free to use the traditional timers which are offered by Ecore.