Let's return to our discussion of processes and threads, this time from the perspective of a real live system. Then, we'll take a look at the function calls used to deal with processes and threads. We know that a process can have one or more threads. (A process that had zero threads wouldn't be able to do anything — there'd be nobody home, so to speak, to actually perform any useful work.) A BlackBerry 10 OS system can have one or more processes. (The same discussion applies — a BlackBerry 10 OS system with zero processes wouldn't do anything.)
So what do these processes and threads do? Ultimately, they form a system — a collection of processes and threads that performs some goal.
At the highest level, the system consists of a number of processes. Each process is responsible for providing a service of some nature — whether it's a filesystem, a display driver, data acquisition module, control module, or whatever.
Within each process, there may be a number of threads. The number of threads varies. One designer using only one thread may accomplish the same functionality as another designer using five threads. Some problems lend themselves to being multi-threaded, and are in fact relatively simple to solve, while other processes lend themselves to being single-threaded, and are difficult to make multi-threaded.
So why not just have one process with a zillion threads? While some OSes force you to code that way, the advantages of breaking things up into multiple processes are many:
The ability to break the problem apart into several independent problems is a powerful concept. It's also at the heart of BlackBerry 10 OS. A BlackBerry 10 OS system consists of many independent modules, each with a certain responsibility. These independent modules are distinct processes. The people at QSS used this trick to develop the modules in isolation, without the modules relying on each other. The only reliance the modules would have on each other is through a small number of well-defined interfaces.
This naturally leads to enhanced maintainability, thanks to the lack of interdependencies. Since each module has its own particular definition, it's reasonably easy to fix one module — especially since it's not tied to any other module.
Reliability, though, is perhaps the most important point. A process, just like a house, has some well-defined borders. A person in a house has a pretty good idea when they're in the house, and when they're not. A thread has a very good idea — if it's accessing memory within the process, it can live. If it steps out of the bounds of the process's address space, it gets killed. This means that two threads, running in different processes, are effectively isolated from each other.
The process address space is maintained and enforced by BlackBerry 10 OS's process manager module. When a process is started, the process manager allocates some memory to it and starts a thread running. The memory is marked as being owned by that process.
This means that if there are multiple threads in that process, and the kernel needs to context-switch between them, it's a very efficient operation — we don't have to change the address space, just which thread is running. If, however, we have to change to another thread in another process, then the process manager gets involved and causes an address space switch as well. Don't worry — while there's a bit more overhead in this additional step, under BlackBerry 10 OS this is still very fast.